diff --git a/build.sh b/build.sh old mode 100644 new mode 100755 diff --git a/src/dbg_info/dbg_info.c b/src/dbg_info/dbg_info.c index 7b5a58a0b..567f3be90 100644 --- a/src/dbg_info/dbg_info.c +++ b/src/dbg_info/dbg_info.c @@ -705,7 +705,48 @@ di_async_tick(void) } else { - rdi_path = str8f(scratch.arena, "%S.rdi", str8_chop_last_dot(og_path)); + // by default, write rdi next to original. but if original lives in + // a typically read-only system location, redirect to user cache dir. + B32 use_user_cache = 0; +#if OS_LINUX + local_persist read_only String8 system_prefixes[] = + { + str8_lit_comp("/usr/"), + str8_lit_comp("/lib/"), + str8_lit_comp("/lib64/"), + str8_lit_comp("/lib32/"), + str8_lit_comp("/opt/"), + str8_lit_comp("/bin/"), + str8_lit_comp("/sbin/"), + str8_lit_comp("/etc/"), + }; + for EachElement(idx, system_prefixes) + { + if(str8_match(str8_prefix(og_path, system_prefixes[idx].size), system_prefixes[idx], 0)) + { + use_user_cache = 1; + break; + } + } +#endif + if(use_user_cache) + { + String8 user_data = get_process_info()->user_program_data_path; + String8 cache_dir = push_str8f(scratch.arena, "%S/raddbg/rdi-cache", user_data); + make_directory(cache_dir); + Temp esc_scratch = temp_begin(scratch.arena); + String8 escaped = push_str8_copy(esc_scratch.arena, og_path); + for(U64 i = 0; i < escaped.size; i += 1) + { + if(escaped.str[i] == '/') { escaped.str[i] = '_'; } + } + rdi_path = push_str8f(scratch.arena, "%S/%S.rdi", cache_dir, str8_chop_last_dot(escaped)); + temp_end(esc_scratch); + } + else + { + rdi_path = str8f(scratch.arena, "%S.rdi", str8_chop_last_dot(og_path)); + } } } @@ -1151,8 +1192,8 @@ di_search_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 * U64 element_count = 0; void *table_base = rdi_section_raw_table_from_kind(rdi, section_kind, &element_count); U64 element_size = rdi_section_element_size_table[section_kind]; - - // rjf: do search + + // rjf: do search Rng1U64 range = lane_range(element_count); for EachInRange(idx, range) { @@ -1170,7 +1211,7 @@ di_search_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 * case RDI_SectionKind_UDTs: { RDI_UDT *udt = (RDI_UDT *)element; - RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, udt->self_type_idx); + RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, udt->self_type_idx); name = fully_qualified_from_rdi_string_and_container(arena, rdi, type_node->user_defined.name_string_idx, udt->container_idx, udt->container_flags); }break; case RDI_SectionKind_SourceFiles: @@ -1192,9 +1233,9 @@ di_search_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 * scratch_end(scratch); }break; default: - { - RDI_Symbol *symbol = (RDI_Symbol *)element; - name = fully_qualified_str8_from_rdi_symbol(arena, rdi, symbol); + { + RDI_Symbol *symbol = (RDI_Symbol *)element; + name = fully_qualified_str8_from_rdi_symbol(arena, rdi, symbol); }break; } if(name.size == 0) { continue; } @@ -1496,12 +1537,12 @@ di_match_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *g Temp scratch = scratch_begin(0, 0); //- rjf: unpack key - U64 index = 0; + U64 index = 0; String8 name = {0}; DI_Key preferred_key = {0}; { U64 key_read_off = 0; - key_read_off += str8_deserial_read_struct(key, key_read_off, &index); + key_read_off += str8_deserial_read_struct(key, key_read_off, &index); key_read_off += str8_deserial_read_struct(key, key_read_off, &preferred_key); key_read_off += str8_deserial_read_struct(key, key_read_off, &name.size); name.str = push_array_no_zero(scratch.arena, U8, name.size); @@ -1634,14 +1675,14 @@ di_match_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *g RDI_NameMapNode *map_node = rdi_name_map_lookup(rdi, &parsed_name_map, leaf_part_of_name.str, leaf_part_of_name.size); U32 matches_count = 0; U32 *matches = rdi_matches_from_map_node(rdi, map_node, &matches_count); - - // rjf: do we have a container? -> filter matches according to container string also + + // rjf: do we have a container? -> filter matches according to container string also U32 *filtered_matches = matches; - U32 filtered_matches_count = matches_count; + U32 filtered_matches_count = matches_count; if(container_part_of_name.size != 0) - { - filtered_matches = push_array(scratch.arena, U32, matches_count); - filtered_matches_count = 0; + { + filtered_matches = push_array(scratch.arena, U32, matches_count); + filtered_matches_count = 0; for EachIndex(match_idx, matches_count) { Temp scratch = scratch_begin(0, 0); @@ -1678,16 +1719,16 @@ di_match_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *g } scratch_end(scratch); } - } - - // rjf: do we have a specific unit queried? -> filter matches according to containing unit -#if 0 - if(target_unit_index != 0) - { - - } -#endif - + } + + // rjf: do we have a specific unit queried? -> filter matches according to containing unit +#if 0 + if(target_unit_index != 0) + { + + } +#endif + // rjf: given matches, pick selected & return as result if(filtered_matches_count != 0) { diff --git a/src/dwarf/dwarf_parse.c b/src/dwarf/dwarf_parse.c index 4b8943b8e..50ea5a080 100644 --- a/src/dwarf/dwarf_parse.c +++ b/src/dwarf/dwarf_parse.c @@ -2696,34 +2696,46 @@ dw_path_from_file(Arena *arena, String8Array dir_table, DW_LineFile *file) Assert(dir_table.count > 0); // find directory and file name associated with the file index - String8 dir = dir_table.v[file->dir_idx]; - String8 path = file->path; - - // infer path style if directory is empty use file name - PathStyle style = path_style_from_str8(dir); + String8 dir = dir_table.v[file->dir_idx]; + String8 comp_dir = dir_table.v[0]; + + // DWARFv5 sec 6.2.4: dir 0 is the current directory of the compilation; + // each additional dir entry is either a full path or is relative to dir 0. + // prepend dir 0 only when the chosen dir is non-zero and not absolute. + PathStyle dir_style = path_style_from_str8(dir); + PathStyle comp_dir_style = path_style_from_str8(comp_dir); + B32 dir_is_relative = (dir_style == PathStyle_Null || dir_style == PathStyle_Relative); + B32 prepend_comp_dir = (file->dir_idx != 0 && dir_is_relative); + + PathStyle style = dir_style; + if (prepend_comp_dir) { + style = comp_dir_style; + } if (style == PathStyle_Null || style == PathStyle_Relative) { - style = path_style_from_str8(file->path); + PathStyle file_style = path_style_from_str8(file->path); + if (file_style != PathStyle_Null && file_style != PathStyle_Relative) { + style = file_style; + } } - + String8List path_list = {0}; { - // directories that start with ".." are relative to the compile unit directory - if (str8_match_lit("..", dir, StringMatchFlag_RightSideSloppy)) { - String8List comp_dir = str8_split_path(scratch.arena, dir_table.v[0]); - str8_list_concat_in_place(&path_list, &comp_dir); + if (prepend_comp_dir) { + String8List comp_dir_list = str8_split_path(scratch.arena, comp_dir); + str8_list_concat_in_place(&path_list, &comp_dir_list); } - + // push directory String8List dir_list = str8_split_path(scratch.arena, dir); str8_list_concat_in_place(&path_list, &dir_list); - + // push file name str8_list_push(scratch.arena, &path_list, file->path); - + // resolve dots in the path str8_path_list_resolve_dots_in_place(&path_list, style); } - + // join path String8 result = str8_path_list_join_by_style(arena, &path_list, style); diff --git a/src/eval/eval_interpret.c b/src/eval/eval_interpret.c index 948c9730e..0aef3987b 100644 --- a/src/eval/eval_interpret.c +++ b/src/eval/eval_interpret.c @@ -942,19 +942,52 @@ e_interpret(String8 bytecode) } }break; - case RDI_EvalOp_PushCfa: + case RDI_EvalOp_CallSiteValue: { - nval.u64 = e_interpret_ctx->cfa; + // DW_OP_entry_value: requires evaluating the embedded sub-bytecode + // in this frame's entry-time register state (i.e. caller's state + // at the call instruction). that state is not currently plumbed + // into the eval context. interpreting in the current ctx gives + // wrong values for spilled args, so report BadOp instead. + // skip past the embedded sub-bytecode in the outer stream so the + // bytes are not interpreted as outer ops on resume. + U32 sub_size = imm.u32; + if(ptr + sub_size <= opl) + { + ptr += sub_size; + } + result.code = E_InterpretationCode_BadOp; + goto done; }break; - - case RDI_EvalOp_CallSiteValue: + case RDI_EvalOp_PartialValue: + { + // DW_OP_piece marker: top-of-stack is a piece of a composite value. + // we do not assemble composites; for single-piece expressions the + // value already on the stack is the result. for multi-piece, only + // the first piece is returned (stack[0] is the final result). + }break; + case RDI_EvalOp_PartialValueBit: + { + // DW_OP_bit_piece marker. same caveat as PartialValue. + }break; + case RDI_EvalOp_Swap: { - // TODO(rjf) - result.code = E_InterpretationCode_BadOp; - goto done; + if(stack_count + 2 > stack_cap) + { + result.code = E_InterpretationCode_InsufficientStackSpace; + goto done; + } + stack[stack_count + 0] = svals[1]; + stack[stack_count + 1] = svals[0]; + stack_count += 2; + }break; + + case RDI_EvalOp_PushCfa: + { + nval.u64 = e_interpret_ctx->cfa; }break; } diff --git a/src/linux/demon/linux_demon.c b/src/linux/demon/linux_demon.c index 0503c2de6..ebb6f238e 100644 --- a/src/linux/demon/linux_demon.c +++ b/src/linux/demon/linux_demon.c @@ -424,12 +424,66 @@ lnx_dmn_rdebug_vaddr_from_memory(int memory_fd, U64 loader_vbase, B32 is_rebased Assert(0 && "failed to read hash table's chain count out of HASH"); } } - else + else if(dynamic_info.gnu_hash_vaddr) { - // TODO: extract count from GNU_HASH - NotImplemented; + // GNU_HASH header: u32 nbuckets, u32 symoffset, u32 bloom_size, u32 bloom_shift, + // followed by bloom[bloom_size] (word size = 4 on 32-bit ELF, 8 on 64-bit), + // buckets[nbuckets] (u32), chains[...] (u32, terminated by entry w/ LSB set). + U32 gnu_header[4] = {0}; + if(lnx_dmn_read(memory_fd, r1u64(dynamic_info.gnu_hash_vaddr, dynamic_info.gnu_hash_vaddr + sizeof(gnu_header)), gnu_header) == sizeof(gnu_header)) + { + U32 nbuckets = gnu_header[0]; + U32 symoffset = gnu_header[1]; + U32 bloom_size = gnu_header[2]; + U64 bloom_word = (elf_class == ELF_Class_64) ? 8 : 4; + U64 buckets_vaddr = dynamic_info.gnu_hash_vaddr + sizeof(gnu_header) + bloom_size * bloom_word; + U64 chain_vaddr = buckets_vaddr + (U64)nbuckets * sizeof(U32); + + // find largest symbol index referenced by any bucket + U32 max_bucket = 0; + for(U32 b = 0; b < nbuckets; b += 1) + { + U32 entry = 0; + if(lnx_dmn_read(memory_fd, r1u64(buckets_vaddr + b*sizeof(U32), buckets_vaddr + (b+1)*sizeof(U32)), &entry) != sizeof(U32)) + { + break; + } + if(entry > max_bucket) { max_bucket = entry; } + } + + if(max_bucket < symoffset) + { + // no symbols in hash; total count is symoffset + symbol_count = symoffset; + } + else + { + // walk chain from max_bucket until terminator (entry w/ LSB set) + U64 idx = max_bucket; + for(;;) + { + U32 chain_entry = 0; + U64 entry_vaddr = chain_vaddr + (idx - symoffset) * sizeof(U32); + if(lnx_dmn_read(memory_fd, r1u64(entry_vaddr, entry_vaddr + sizeof(U32)), &chain_entry) != sizeof(U32)) + { + break; + } + if(chain_entry & 1) + { + symbol_count = idx + 1; + break; + } + idx += 1; + if(idx - max_bucket > (1u<<24)) + { + // sanity bound: don't loop forever on a corrupt chain + break; + } + } + } + } } - + // scan symbol table for the rendezvous symbol if(dynamic_info.symtab_vaddr && dynamic_info.symtab_entry_size && symbol_count) { diff --git a/src/linux/window_manager/linux_window_manager.c b/src/linux/window_manager/linux_window_manager.c index f3726fa01..1f3e4d0d4 100644 --- a/src/linux/window_manager/linux_window_manager.c +++ b/src/linux/window_manager/linux_window_manager.c @@ -117,15 +117,32 @@ wm_window_open(Rng2F32 rect, WM_WindowFlags flags, String8 title) DLLPushBack(os_lnx_gfx_state->first_window, os_lnx_gfx_state->last_window, w); //- rjf: create window & equip with x11 info + Visual *visual = os_lnx_gfx_state->window_visual; + int depth = os_lnx_gfx_state->window_depth; + Colormap colormap = os_lnx_gfx_state->window_colormap; + unsigned long attr_mask = 0; + XSetWindowAttributes window_attribs = {0}; + if(visual == 0) + { + visual = (Visual *)CopyFromParent; + depth = CopyFromParent; + } + else + { + window_attribs.background_pixmap = None; + window_attribs.border_pixel = 0; + window_attribs.colormap = colormap; + attr_mask = CWBackPixmap|CWBorderPixel|CWColormap; + } w->window = XCreateWindow(os_lnx_gfx_state->display, XDefaultRootWindow(os_lnx_gfx_state->display), 0, 0, resolution.x, resolution.y, 0, - CopyFromParent, + depth, InputOutput, - CopyFromParent, - 0, - 0); + visual, + attr_mask, + &window_attribs); XSelectInput(os_lnx_gfx_state->display, w->window, ExposureMask| PointerMotionMask| @@ -190,6 +207,7 @@ wm_window_first_paint(WM_Window handle) if(wm_window_match(handle, wm_window_zero())) {return;} LNX_WM_Window *w = (LNX_WM_Window *)handle.u64[0]; XMapWindow(os_lnx_gfx_state->display, w->window); + XFlush(os_lnx_gfx_state->display); } internal void diff --git a/src/linux/window_manager/linux_window_manager.h b/src/linux/window_manager/linux_window_manager.h index 7ee9ddb49..d4f03639d 100644 --- a/src/linux/window_manager/linux_window_manager.h +++ b/src/linux/window_manager/linux_window_manager.h @@ -46,6 +46,9 @@ struct LNX_WM_GfxState Cursor cursors[WM_Cursor_COUNT]; WM_Cursor last_set_cursor; WM_SystemInfo gfx_info; + Visual *window_visual; + int window_depth; + Colormap window_colormap; }; //////////////////////////////// diff --git a/src/rdi_from_dwarf/rdi_from_dwarf.c b/src/rdi_from_dwarf/rdi_from_dwarf.c index 445281a65..8bcaa9c65 100644 --- a/src/rdi_from_dwarf/rdi_from_dwarf.c +++ b/src/rdi_from_dwarf/rdi_from_dwarf.c @@ -2858,11 +2858,23 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) DW_LineFile *src = lookup->file; RDIM_SrcFile *dst = rdim_src_file_chunk_list_push(arena, &g_d2r_shared.src_files, D2R_SRC_FILE_CAP); - // make file path + // make file path -- DWARFv5 sec 6.2.4: dir entries other than 0 may be + // relative to dir 0 (the compilation directory). prepend dir 0 when + // the chosen dir is relative. String8 path; { + String8 dir = lookup->vm->header.dir_table.v[src->dir_idx]; + String8 comp_dir = lookup->vm->header.dir_table.v[0]; + PathStyle dir_style = path_style_from_str8(dir); + B32 dir_is_relative = (dir_style == PathStyle_Null || dir_style == PathStyle_Relative); + B32 prepend_comp_dir = (src->dir_idx != 0 && dir_is_relative); String8List path_list = {0}; - str8_list_push_node(&path_list, &(String8Node){ .string = lookup->vm->header.dir_table.v[src->dir_idx] }); + if (prepend_comp_dir) { + String8List comp_dir_list = str8_split_path(scratch.arena, comp_dir); + str8_list_concat_in_place(&path_list, &comp_dir_list); + } + String8List dir_list = str8_split_path(scratch.arena, dir); + str8_list_concat_in_place(&path_list, &dir_list); str8_list_push_node(&path_list, &(String8Node){ .string = src->path }); path = str8_path_list_join_by_style(arena, &path_list, path_style); } diff --git a/src/render/opengl/linux/egl/render_opengl_linux_egl.c b/src/render/opengl/linux/egl/render_opengl_linux_egl.c index 165ffc3ea..6a51d6988 100644 --- a/src/render/opengl/linux/egl/render_opengl_linux_egl.c +++ b/src/render/opengl/linux/egl/render_opengl_linux_egl.c @@ -51,7 +51,63 @@ r_ogl_os_init(CmdLine *cmdln) wm_graphical_message(1, str8_lit("Fatal Error"), str8_lit("Couldn't initialize EGL API to OpenGL.")); abort_self(1); } - + + //- choose EGL config, extract matching X11 visual/colormap, publish to os layer + { + EGLint config_filter[] = + { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT, + EGL_CONFORMANT, EGL_OPENGL_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, + EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_DEPTH_SIZE, 24, + EGL_STENCIL_SIZE, 8, + EGL_NONE, + }; + EGLConfig configs[256] = {0}; + EGLint configs_count = 0; + if(!eglChooseConfig(r_ogl_lnx_state->display, config_filter, configs, ArrayCount(configs), &configs_count) || configs_count == 0) + { + wm_graphical_message(1, str8_lit("Fatal Error"), str8_lit("Couldn't choose EGL configuration.")); + abort_self(1); + } + int screen = DefaultScreen(os_lnx_gfx_state->display); + XVisualInfo vi_template = {0}; + XVisualInfo *vi = 0; + int vi_count = 0; + for(EGLint idx = 0; idx < configs_count && vi == 0; idx += 1) + { + EGLint native_visual_id = 0; + if(!eglGetConfigAttrib(r_ogl_lnx_state->display, configs[idx], EGL_NATIVE_VISUAL_ID, &native_visual_id) || native_visual_id == 0) + { + continue; + } + vi_template.visualid = native_visual_id; + vi_template.screen = screen; + vi = XGetVisualInfo(os_lnx_gfx_state->display, VisualIDMask|VisualScreenMask, &vi_template, &vi_count); + if(vi != 0 && vi_count > 0) + { + r_ogl_lnx_state->config = configs[idx]; + break; + } + if(vi != 0) { XFree(vi); vi = 0; } + } + if(vi == 0 || r_ogl_lnx_state->config == 0) + { + wm_graphical_message(1, str8_lit("Fatal Error"), str8_lit("Couldn't find an EGL config with a matching X11 visual.")); + abort_self(1); + } + os_lnx_gfx_state->window_visual = vi->visual; + os_lnx_gfx_state->window_depth = vi->depth; + os_lnx_gfx_state->window_colormap = XCreateColormap(os_lnx_gfx_state->display, + XRootWindow(os_lnx_gfx_state->display, vi->screen), + vi->visual, AllocNone); + XFree(vi); + } + //- rjf: construct context { B32 debug_mode = cmd_line_has_flag(cmdln, str8_lit("opengl_debug")); @@ -66,16 +122,23 @@ r_ogl_os_init(CmdLine *cmdln) debug_mode ? EGL_CONTEXT_OPENGL_DEBUG : EGL_NONE, EGL_TRUE, EGL_NONE, }; - r_ogl_lnx_state->context = eglCreateContext(r_ogl_lnx_state->display, 0, EGL_NO_CONTEXT, options); + r_ogl_lnx_state->context = eglCreateContext(r_ogl_lnx_state->display, r_ogl_lnx_state->config, EGL_NO_CONTEXT, options); if(r_ogl_lnx_state->context == EGL_NO_CONTEXT) { wm_graphical_message(1, str8_lit("Fatal Error"), str8_lit("Couldn't create OpenGL context with EGL.")); abort_self(1); } } - - eglMakeCurrent(r_ogl_lnx_state->display, 0, 0, r_ogl_lnx_state->context); - glDrawBuffer(GL_BACK); + + //- bind context to 1x1 pbuffer so GL calls work before any window exists + { + EGLint pbuffer_attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE }; + EGLSurface init_surface = eglCreatePbufferSurface(r_ogl_lnx_state->display, r_ogl_lnx_state->config, pbuffer_attribs); + if(init_surface == EGL_NO_SURFACE || !eglMakeCurrent(r_ogl_lnx_state->display, init_surface, init_surface, r_ogl_lnx_state->context)) + { + eglMakeCurrent(r_ogl_lnx_state->display, EGL_NO_SURFACE, EGL_NO_SURFACE, r_ogl_lnx_state->context); + } + } } internal R_Handle @@ -97,60 +160,11 @@ r_ogl_os_window_equip(WM_Window window) EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_SRGB, EGL_NONE, }; - if(r_ogl_lnx_state->config == 0) - { - //- rjf: get all EGL configs - EGLConfig configs[256] = {0}; - EGLint configs_count = 0; - { - EGLint options[] = - { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_CONFORMANT, EGL_OPENGL_BIT, - EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, - EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER, - - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_DEPTH_SIZE, 24, - EGL_STENCIL_SIZE, 8, - - EGL_NONE, - }; - if(!eglChooseConfig(r_ogl_lnx_state->display, options, configs, ArrayCount(configs), &configs_count) || configs_count == 0) - { - wm_graphical_message(1, str8_lit("Fatal Error"), str8_lit("Couldn't choose EGL configuration.")); - abort_self(1); - } - } - - //- rjf: actually choose the egl config - { - EGLint config_options[] = - { - EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_SRGB, - EGL_NONE, - }; - for(U32 idx = 0; idx < configs_count; idx += 1) - { - w->surface = eglCreateWindowSurface(r_ogl_lnx_state->display, configs[idx], window_os->window, config_options); - if(w->surface != EGL_NO_SURFACE) - { - r_ogl_lnx_state->config = configs[idx]; - break; - } - } - if(r_ogl_lnx_state->config == 0) - { - wm_graphical_message(1, str8_lit("Fatal Error"), str8_lit("Couldn't find a suitable EGL configuration.")); - abort_self(1); - } - } - } - else + w->surface = eglCreateWindowSurface(r_ogl_lnx_state->display, r_ogl_lnx_state->config, window_os->window, surface_options); + if(w->surface == EGL_NO_SURFACE) { - w->surface = eglCreateWindowSurface(r_ogl_lnx_state->display, r_ogl_lnx_state->config, window_os->window, surface_options); + EGLint surface_options_linear[] = { EGL_NONE }; + w->surface = eglCreateWindowSurface(r_ogl_lnx_state->display, r_ogl_lnx_state->config, window_os->window, surface_options_linear); } if(w->surface == EGL_NO_SURFACE) { @@ -175,15 +189,16 @@ r_ogl_os_window_unequip(WM_Window os, R_Handle r) internal void r_ogl_os_select_window(WM_Window os, R_Handle r) { - LNX_WM_Window *w = (LNX_WM_Window *)os.u64[0]; - R_OGL_LNX_Window *w_r = (R_OGL_LNX_Window *)r.u64[0]; + // r is the outer R_OGL_Window* wrapper; the os-layer handle is .os + R_OGL_Window *outer = (R_OGL_Window *)r.u64[0]; + R_OGL_LNX_Window *w_r = (R_OGL_LNX_Window *)outer->os.u64[0]; eglMakeCurrent(r_ogl_lnx_state->display, w_r->surface, w_r->surface, r_ogl_lnx_state->context); } internal void r_ogl_os_window_swap(WM_Window os, R_Handle r) { - LNX_WM_Window *w = (LNX_WM_Window *)os.u64[0]; - R_OGL_LNX_Window *w_r = (R_OGL_LNX_Window *)r.u64[0]; + R_OGL_Window *outer = (R_OGL_Window *)r.u64[0]; + R_OGL_LNX_Window *w_r = (R_OGL_LNX_Window *)outer->os.u64[0]; eglSwapBuffers(r_ogl_lnx_state->display, w_r->surface); } diff --git a/src/render/opengl/linux/egl/render_opengl_linux_egl.h b/src/render/opengl/linux/egl/render_opengl_linux_egl.h index 77d687d77..27a0ba888 100644 --- a/src/render/opengl/linux/egl/render_opengl_linux_egl.h +++ b/src/render/opengl/linux/egl/render_opengl_linux_egl.h @@ -7,6 +7,7 @@ #define glTexImage3D glTexImage3D__static #define glTexSubImage3D glTexSubImage3D__static #define glActiveTexture glActiveTexture__static +#include #include #include #undef glTexImage3D diff --git a/src/render/opengl/linux/glx/render_opengl_linux_glx.c b/src/render/opengl/linux/glx/render_opengl_linux_glx.c index 8b0a34a77..4b75a1960 100644 --- a/src/render/opengl/linux/glx/render_opengl_linux_glx.c +++ b/src/render/opengl/linux/glx/render_opengl_linux_glx.c @@ -50,12 +50,22 @@ r_ogl_os_init(CmdLine *cmdln) } GLXFBConfig framebuffer_config = framebuffer_configs[0]; XFree(framebuffer_configs); - - //- rjf: construct set-window-attributes - XSetWindowAttributes set_window_attributes = {0}; - set_window_attributes.background_pixmap = None; - set_window_attributes.border_pixel = 0; - set_window_attributes.event_mask = StructureNotifyMask; + + //- extract visual/colormap from chosen fbconfig, publish to os layer + { + XVisualInfo *vi = glXGetVisualFromFBConfig(os_lnx_gfx_state->display, framebuffer_config); + if(vi == 0) + { + wm_graphical_message(1, str8_lit("Fatal Error"), str8_lit("Could not get visual from GLX framebuffer config.")); + abort_self(1); + } + os_lnx_gfx_state->window_visual = vi->visual; + os_lnx_gfx_state->window_depth = vi->depth; + os_lnx_gfx_state->window_colormap = XCreateColormap(os_lnx_gfx_state->display, + XRootWindow(os_lnx_gfx_state->display, vi->screen), + vi->visual, AllocNone); + XFree(vi); + } //- rjf: construct context { @@ -96,6 +106,9 @@ r_ogl_os_select_window(WM_Window os, R_Handle r) { LNX_WM_Window *w = (LNX_WM_Window *)os.u64[0]; glXMakeCurrent(os_lnx_gfx_state->display, w->window, r_ogl_lnx_ctx); + // ensure default framebuffer writes target the back buffer; on some drivers + // GL_DRAW_BUFFER stays GL_NONE if a context was first made current without a drawable. + glDrawBuffer(GL_BACK); } internal void