static dynamic_string getfullpath(const char *filename) { char buf[PATH_MAX]; // Get the full path to our executable. It should be running in vogl/bin/x86_64 (or i386). if ((readlink("/proc/self/exe", buf, sizeof(buf)) <= 0)) errorf(VOGL_FUNCTION_INFO_CSTR, "ERROR: readlink failed '%s.'\n", strerror(errno)); // Get just the directory name and relative path to libvogltrace.so. dynamic_string filedir = dirname(buf); filedir += "/"; filedir += filename; // Trim all the relative path parts. char *vogltracepath = realpath(filedir.c_str(), NULL); if (!vogltracepath) { vogl_warning_printf("\nWARNING: realpath failed: '%s.' Does '%s' exist?\n", strerror(errno), filename); return filename; } // Make sure our libvogltrace.so exists. if(access(vogltracepath, F_OK) != 0) { vogl_warning_printf("\nWARNING: %s file does not exist.\n", vogltracepath); return filename; } return vogltracepath; }
bool vogleditor_traceReplayer::applying_snapshot_and_process_resize(const vogl_gl_state_snapshot* pSnapshot) { vogl_gl_replayer::status_t status = m_pTraceReplayer->begin_applying_snapshot(pSnapshot, false); bool bStatus = true; while (status == vogl_gl_replayer::cStatusResizeWindow) { vogl_warning_printf("%s: Waiting for window to resize\n", VOGL_METHOD_NAME); // Pump X events in case the window is resizing if (process_x_events()) { status = m_pTraceReplayer->process_pending_window_resize(); } else { bStatus = false; break; } } if (bStatus && status != vogl_gl_replayer::cStatusOK) { vogl_error_printf("%s: Replay unable to apply snapshot\n", VOGL_FUNCTION_NAME); bStatus = false; } return bStatus; }
char *file_utils::get_exec_filename(char *pPath, size_t dest_len) { #if VOGL_HAS_PROC_FILESYSTEM ssize_t s = readlink("/proc/self/exe", pPath, dest_len); if (s >= 0) { pPath[s] = '\0'; return pPath; } VOGL_VERIFY(0); pPath[0] = '\0'; return pPath; #elif defined(VOGL_USE_OSX_API) char **argv = *_NSGetArgv(); strncpy(pPath, argv[0], dest_len); vogl_warning_printf("UNTESTED: file_utils::get_exec_filename returning [%s]\n", pPath); return pPath; #elif defined(VOGL_USE_WIN32_API) DWORD result = GetModuleFileNameA(0, pPath, safe_int_cast<DWORD>(dest_len)); VOGL_VERIFY(result != 0); return pPath; #else VOGL_ASSUME(!"Implement get_exec_filename for this platform."); #endif }
bool vogl_vao_state::restore(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 &handle) const { VOGL_FUNC_TRACER VOGL_CHECK_GL_ERROR; if (!m_is_valid) return false; vogl_scoped_binding_state orig_binding(GL_VERTEX_ARRAY, GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER); if ((!m_snapshot_handle) && (!handle)) { GL_ENTRYPOINT(glBindVertexArray)(0); VOGL_CHECK_GL_ERROR; } else { if (!handle) { GLuint handle32 = 0; GL_ENTRYPOINT(glGenVertexArrays)(1, &handle32); if ((vogl_check_gl_error()) || (!handle32)) return false; handle = handle32; if (m_snapshot_handle) { remapper.declare_handle(VOGL_NAMESPACE_VERTEX_ARRAYS, m_snapshot_handle, handle, GL_NONE); VOGL_ASSERT(remapper.remap_handle(VOGL_NAMESPACE_VERTEX_ARRAYS, m_snapshot_handle) == handle); } } if (m_has_been_bound) { GL_ENTRYPOINT(glBindVertexArray)(static_cast<GLuint>(handle)); VOGL_CHECK_GL_ERROR; } } if (m_has_been_bound) { GL_ENTRYPOINT(glBindBuffer)(GL_ELEMENT_ARRAY_BUFFER, static_cast<GLuint>(remapper.remap_handle(VOGL_NAMESPACE_BUFFERS, m_element_array_binding))); VOGL_CHECK_GL_ERROR; if (m_vertex_attribs.size() > context_info.get_max_vertex_attribs()) { vogl_warning_printf("Saved VAO state has %u attribs, but context only allows %u attribs\n", m_vertex_attribs.size(), context_info.get_max_vertex_attribs()); } for (uint32_t i = 0; i < math::minimum<uint32_t>(context_info.get_max_vertex_attribs(), m_vertex_attribs.size()); i++) { const vogl_vertex_attrib_desc &desc = m_vertex_attribs[i]; GL_ENTRYPOINT(glBindBuffer)(GL_ARRAY_BUFFER, static_cast<GLuint>(remapper.remap_handle(VOGL_NAMESPACE_BUFFERS, desc.m_array_binding))); VOGL_CHECK_GL_ERROR; vogl_trace_ptr_value trace_ptr_val = desc.m_pointer; vogl_trace_ptr_value restore_ptr_val = trace_ptr_val; if ((!desc.m_array_binding) && (trace_ptr_val) && (context_info.is_compatibility_profile())) restore_ptr_val = remapper.remap_vertex_attrib_ptr(i, trace_ptr_val); void *pRestore_ptr = reinterpret_cast<void *>(restore_ptr_val); if ((handle) && (desc.m_array_binding == 0)) { // If it's a non-default VAO, and there's no array binding, we can't call glVertexAttribPointer() because it's not allowed by AMD drivers (it thinks we're trying to set client side array data) // "OpenGL: glVertexAttribPointer failed because it is not allowed to specify a client-side vertex or element array when a non-default vertex array object is bound (GL_INVALID_OPERATION) [source=API type=ERROR severity=HIGH id=2100]" // Sanity checks. if ((pRestore_ptr != NULL) || (desc.m_stride) || (desc.m_enabled)) { vogl_warning_printf("Can't bind client side vertex array data on a non-default VAO, trace handle %u GL handle %u, restore ptr %p, size %i stride %i enabled %u\n", m_snapshot_handle, static_cast<uint32_t>(handle), pRestore_ptr, desc.m_size, desc.m_stride, desc.m_enabled); } } else { if (desc.m_integer) { GL_ENTRYPOINT(glVertexAttribIPointer)(i, desc.m_size, desc.m_type, desc.m_stride, pRestore_ptr); VOGL_CHECK_GL_ERROR; } else { GL_ENTRYPOINT(glVertexAttribPointer)(i, desc.m_size, desc.m_type, desc.m_normalized, desc.m_stride, pRestore_ptr); VOGL_CHECK_GL_ERROR; } } GL_ENTRYPOINT(glVertexAttribDivisor)(i, desc.m_divisor); VOGL_CHECK_GL_ERROR; if (desc.m_enabled) { GL_ENTRYPOINT(glEnableVertexAttribArray)(i); VOGL_CHECK_GL_ERROR; } else { GL_ENTRYPOINT(glDisableVertexAttribArray)(i); VOGL_CHECK_GL_ERROR; } } } return true; }
// TODO: return bool void vogleditor_QApiCallTreeModel::setupModelData(vogl_trace_file_reader* pTrace_reader, vogleditor_apiCallTreeItem *parent) { const vogl_trace_stream_start_of_file_packet &sof_packet = pTrace_reader->get_sof_packet(); VOGL_NOTE_UNUSED(sof_packet); uint64_t total_swaps = 0; // TODO probably need to handle eof_packet //bool found_eof_packet = false; // make a PendingFrame node to hold the api calls // this will remain in the pending state until the first // api call is seen, then it will be made the CurFrame and // appended to the parent vogleditor_frameItem* pCurFrame = NULL; vogleditor_apiCallTreeItem* pCurParent = parent; // Make a PendingSnapshot that may or may not be populated when reading the trace. // This snapshot will be assigned to the next API call that occurs. vogleditor_gl_state_snapshot* pPendingSnapshot = NULL; m_trace_ctypes.init(pTrace_reader->get_sof_packet().m_pointer_sizes); for ( ; ; ) { vogl_trace_file_reader::trace_file_reader_status_t read_status = pTrace_reader->read_next_packet(); if ((read_status != vogl_trace_file_reader::c*K) && (read_status != vogl_trace_file_reader::cEOF)) { vogl_error_printf("Failed reading from trace file!\n"); break; } if (read_status == vogl_trace_file_reader::cEOF) { vogl_printf("At trace file EOF on swap %" PRIu64 "\n", total_swaps); break; } const vogl::vector<uint8> &packet_buf = pTrace_reader->get_packet_buf(); VOGL_NOTE_UNUSED(packet_buf); const vogl_trace_stream_packet_base &base_packet = pTrace_reader->get_base_packet(); VOGL_NOTE_UNUSED(base_packet); const vogl_trace_gl_entrypoint_packet *pGL_packet = NULL; if (pTrace_reader->get_packet_type() == cTSPTGLEntrypoint) { vogl_trace_packet* pTrace_packet = vogl_new(vogl_trace_packet, &m_trace_ctypes); if (!pTrace_packet->deserialize(pTrace_reader->get_packet_buf().get_ptr(), pTrace_reader->get_packet_buf().size(), false)) { console::error("%s: Failed parsing GL entrypoint packet\n", VOGL_FUNCTION_NAME); break; } pGL_packet = &pTrace_reader->get_packet<vogl_trace_gl_entrypoint_packet>(); gl_entrypoint_id_t entrypoint_id = static_cast<gl_entrypoint_id_t>(pGL_packet->m_entrypoint_id); if (entrypoint_id == VOGL_ENTRYPOINT_glInternalTraceCommandRAD) { // Check if this is a state snapshot. // This is entirely optional since the client is designed to dynamically get new snapshots // if they don't exist. GLuint cmd = pTrace_packet->get_param_value<GLuint>(0); GLuint size = pTrace_packet->get_param_value<GLuint>(1); VOGL_NOTE_UNUSED(size); if (cmd == cITCRKeyValueMap) { key_value_map &kvm = pTrace_packet->get_key_value_map(); dynamic_string cmd_type(kvm.get_string("command_type")); if (cmd_type == "state_snapshot") { dynamic_string id(kvm.get_string("binary_id")); if (id.is_empty()) { vogl_warning_printf("%s: Missing binary_id field in glInternalTraceCommandRAD key_valye_map command type: \"%s\"\n", VOGL_FUNCTION_NAME, cmd_type.get_ptr()); continue; } uint8_vec snapshot_data; { timed_scope ts("get_multi_blob_manager().get"); if (!pTrace_reader->get_multi_blob_manager().get(id, snapshot_data) || (snapshot_data.is_empty())) { vogl_warning_printf("%s: Failed reading snapshot blob data \"%s\"!\n", VOGL_FUNCTION_NAME, id.get_ptr()); continue; } } json_document doc; { timed_scope ts("doc.binary_deserialize"); if (!doc.binary_deserialize(snapshot_data) || (!doc.get_root())) { vogl_warning_printf("%s: Failed deserializing JSON snapshot blob data \"%s\"!\n", VOGL_FUNCTION_NAME, id.get_ptr()); continue; } } vogl_gl_state_snapshot* pGLSnapshot = vogl_new(vogl_gl_state_snapshot); pPendingSnapshot = vogl_new(vogleditor_gl_state_snapshot, pGLSnapshot); timed_scope ts("pPendingSnapshot->deserialize"); if (!pPendingSnapshot->get_snapshot()->deserialize(*doc.get_root(), pTrace_reader->get_multi_blob_manager(), &m_trace_ctypes)) { vogl_delete(pPendingSnapshot); pPendingSnapshot = NULL; vogl_warning_printf("%s: Failed deserializing snapshot blob data \"%s\"!\n", VOGL_FUNCTION_NAME, id.get_ptr()); } } } continue; } const gl_entrypoint_desc_t &entrypoint_desc = g_vogl_entrypoint_descs[entrypoint_id]; QString funcCall = entrypoint_desc.m_pName; // format parameters funcCall.append("( "); dynamic_string paramStr; for (uint param_index = 0; param_index < pTrace_packet->total_params(); param_index++) { if (param_index != 0) funcCall.append(", "); paramStr.clear(); pTrace_packet->pretty_print_param(paramStr, param_index, false); funcCall.append(paramStr.c_str()); } funcCall.append(" )"); if (pTrace_packet->has_return_value()) { funcCall.append(" = "); paramStr.clear(); pTrace_packet->pretty_print_return_value(paramStr, false); funcCall.append(paramStr.c_str()); } // if we don't have a current frame, make a new frame node // and append it to the parent if (pCurFrame == NULL) { pCurFrame = vogl_new(vogleditor_frameItem, total_swaps); vogleditor_apiCallTreeItem* pNewFrameNode = vogl_new(vogleditor_apiCallTreeItem, pCurFrame, pCurParent); pCurParent->appendChild(pNewFrameNode); m_itemList.append(pNewFrameNode); if (pPendingSnapshot != NULL) { pCurFrame->set_snapshot(pPendingSnapshot); pPendingSnapshot = NULL; } // update current parent pCurParent = pNewFrameNode; } // make item and node for the api call vogleditor_apiCallItem* pCallItem = vogl_new(vogleditor_apiCallItem, pCurFrame, pTrace_packet, *pGL_packet); pCurFrame->appendCall(pCallItem); if (pPendingSnapshot != NULL) { pCallItem->set_snapshot(pPendingSnapshot); pPendingSnapshot = NULL; } vogleditor_apiCallTreeItem* item = vogl_new(vogleditor_apiCallTreeItem, funcCall, pCallItem, pCurParent); pCurParent->appendChild(item); m_itemList.append(item); if (vogl_is_swap_buffers_entrypoint(entrypoint_id)) { total_swaps++; // reset the CurParent back to the original parent so that the next frame will be at the root level pCurParent = parent; // reset the CurFrame so that a new frame node will be created on the next api call pCurFrame = NULL; } else if (vogl_is_start_nested_entrypoint(entrypoint_id)) { // Nest logically paired blocks of gl calls including terminating // nest call pCurParent = item; } else if (vogl_is_end_nested_entrypoint(entrypoint_id)) { // move the parent back one level of the hierarchy, to its own parent // (but not past Frame parent [e.g., unpaired "end" operation]) if (pCurParent->parent() != parent) pCurParent = pCurParent->parent(); } } if (pTrace_reader->get_packet_type() == cTSPTEOF) { //found_eof_packet = true; vogl_printf("Found trace file EOF packet on swap %" PRIu64 "\n", total_swaps); break; } } }
//---------------------------------------------------------------------------------------------------------------------- // Function vogl_init_gl_entrypoint_descs //---------------------------------------------------------------------------------------------------------------------- void vogl_init_gl_entrypoint_descs() { gl_entrypoint_param_desc_t *pDst = &g_vogl_entrypoint_param_descs[0][0]; #define DEF_FUNCTION_BEGIN(exported, category, ret, ret_type, num_params, name, args, params) #define DEF_FUNCTION_INFO(namespace_index, return_spectype, category, version, profile, deprecated, is_whitelisted, is_nullable, whitelisted_for_displaylists, listable) #define DEF_FUNCTION_BEGIN_PARAMS \ { \ gl_entrypoint_param_desc_t *pCur = pDst; #define DEF_FUNCTION_IN_VALUE_PARAM(namespace_index, spectype, type, ctype, name) \ { \ pCur->m_pSpec_type = #spectype; \ pCur->m_pName = #name; \ pCur->m_ctype = ctype; \ pCur->m_class = VOGL_VALUE_PARAM; \ pCur->m_input = true; \ pCur->m_namespace = (vogl_namespace_t)namespace_index; \ ++pCur; \ } #define DEF_FUNCTION_IN_REFERENCE_PARAM(namespace_index, spectype, type, ctype, name) \ { \ pCur->m_pSpec_type = #spectype; \ pCur->m_pName = #name; \ pCur->m_ctype = ctype; \ pCur->m_class = VOGL_REF_PARAM; \ pCur->m_input = true; \ pCur->m_namespace = (vogl_namespace_t)namespace_index; \ ++pCur; \ } #define DEF_FUNCTION_IN_ARRAY_PARAM(namespace_index, spectype, type, ctype, name, size) \ { \ pCur->m_pSpec_type = #spectype; \ pCur->m_pName = #name; \ pCur->m_ctype = ctype; \ pCur->m_class = VOGL_ARRAY_PARAM; \ pCur->m_input = true; \ pCur->m_pSize = #size; \ pCur->m_namespace = (vogl_namespace_t)namespace_index; \ ++pCur; \ } #define DEF_FUNCTION_OUT_REFERENCE_PARAM(namespace_index, spectype, type, ctype, name) \ { \ pCur->m_pSpec_type = #spectype; \ pCur->m_pName = #name; \ pCur->m_ctype = ctype; \ pCur->m_class = VOGL_ARRAY_PARAM; \ pCur->m_input = false; \ pCur->m_namespace = (vogl_namespace_t)namespace_index; \ ++pCur; \ } #define DEF_FUNCTION_OUT_ARRAY_PARAM(namespace_index, spectype, type, ctype, name, size) \ { \ pCur->m_pSpec_type = #spectype; \ pCur->m_pName = #name; \ pCur->m_ctype = ctype; \ pCur->m_class = VOGL_ARRAY_PARAM; \ pCur->m_input = false; \ pCur->m_pSize = #size; \ pCur->m_namespace = (vogl_namespace_t)namespace_index; \ ++pCur; \ } #define DEF_FUNCTION_END_PARAMS \ VOGL_ASSERT((pCur - pDst) <= VOGL_MAX_ENTRYPOINT_PARAMETERS); \ } #define DEF_FUNCTION_RETURN(spectype, type, ctype) #define DEF_FUNCTION_END(exported, category, ret, ret_type, num_params, name, args, params) pDst += VOGL_MAX_ENTRYPOINT_PARAMETERS; #include "gl_glx_cgl_wgl_func_descs.inc" for (uint32_t i = 0; i < VOGL_ARRAY_SIZE(g_custom_array_size_macro_indices); i++) { uint32_t idx = g_custom_array_size_macro_indices[i]; uint32_t func = idx >> 16; uint32_t param = idx & 0xFFFF; VOGL_ASSERT(func < VOGL_NUM_ENTRYPOINTS); VOGL_ASSERT(param < g_vogl_entrypoint_descs[func].m_num_params); g_vogl_entrypoint_param_descs[func][param].m_has_custom_array_size_macro = true; } for (uint32_t i = 0; i < VOGL_NUM_ENTRYPOINTS; i++) { gl_entrypoint_desc_t &desc = g_vogl_entrypoint_descs[i]; VOGL_ASSERT(desc.m_return_namespace >= VOGL_NAMESPACE_UNKNOWN); VOGL_ASSERT(desc.m_return_namespace < VOGL_TOTAL_NAMESPACES); if (strcmp(desc.m_pName, "glGenTextures") == 0) { if (g_vogl_entrypoint_param_descs[i][1].m_namespace != VOGL_NAMESPACE_TEXTURES) { vogl_error_printf("vogl_namespace_t enum is bad, please rebuild"); exit(EXIT_FAILURE); } } if (desc.m_return_ctype != VOGL_VOID) { if ((size_t)get_vogl_process_gl_ctypes()[desc.m_return_ctype].m_size < 1) vogl_warning_printf("function %s's return ctype %s is too small\n", desc.m_pName, get_vogl_process_gl_ctypes()[desc.m_return_ctype].m_pName); if ((size_t)get_vogl_process_gl_ctypes()[desc.m_return_ctype].m_size > sizeof(uint64_t)) vogl_warning_printf("function %s's return ctype %s is too large\n", desc.m_pName, get_vogl_process_gl_ctypes()[desc.m_return_ctype].m_pName); } for (uint32_t j = 0; j < desc.m_num_params; j++) { if ((size_t)get_vogl_process_gl_ctypes()[g_vogl_entrypoint_param_descs[i][j].m_ctype].m_size < 1) vogl_warning_printf("param %u of function %s ctype %s is too small\n", j, desc.m_pName, get_vogl_process_gl_ctypes()[g_vogl_entrypoint_param_descs[i][j].m_ctype].m_pName); if ((size_t)get_vogl_process_gl_ctypes()[g_vogl_entrypoint_param_descs[i][j].m_ctype].m_size > sizeof(uint64_t)) vogl_warning_printf("param %u of function %s ctype %s is too large\n", j, desc.m_pName, get_vogl_process_gl_ctypes()[g_vogl_entrypoint_param_descs[i][j].m_ctype].m_pName); } desc.m_pAPI_prefix = "GL"; // FIXME: Add more prefixes as we add platforms. voglgen should probably supply this. // They must correspond with the GL enum prefixes in glx_enum_desc.inc, gl_enum_desc.inc, etc. if ((desc.m_pName[0] == 'w') && (desc.m_pName[1] == 'g') && (desc.m_pName[2] == 'l')) desc.m_pAPI_prefix = "WGL"; else if ((desc.m_pName[0] == 'C') && (desc.m_pName[1] == 'G') && (desc.m_pName[2] == 'L')) desc.m_pAPI_prefix = "CGL"; else if ((desc.m_pName[0] == 'g') && (desc.m_pName[1] == 'l') && (desc.m_pName[2] == 'X')) desc.m_pAPI_prefix = "GLX"; else if ((desc.m_pName[0] == 'g') && (desc.m_pName[1] == 'l')) desc.m_pAPI_prefix = "GL"; else { vogl_warning_printf("Unknown function prefix: %s\n", desc.m_pName); } } for (uint32_t i = 0; i < VOGL_NUM_ENTRYPOINTS; i++) { get_vogl_entrypoint_hashmap().insert(g_vogl_entrypoint_descs[i].m_pName, static_cast<gl_entrypoint_id_t>(i)); } }
bool vogl_binary_trace_file_reader::open(const char *pFilename, const char *pLoose_file_path) { VOGL_FUNC_TRACER close(); if (!init_loose_file_blob_manager(pFilename, pLoose_file_path)) return false; if (!m_trace_stream.open(pFilename, cDataStreamReadable | cDataStreamSeekable, true)) { close(); return false; } m_trace_file_size = m_trace_stream.get_size(); if (m_trace_stream.read(&m_sof_packet, sizeof(m_sof_packet)) != sizeof(m_sof_packet)) { close(); return false; } if (!m_sof_packet.full_validation(sizeof(m_sof_packet))) { vogl_error_printf("%s: Trace file failed validation!\n", VOGL_FUNCTION_INFO_CSTR); close(); return false; } if (m_sof_packet.m_version < static_cast<uint16_t>(VOGL_TRACE_FILE_MINIMUM_COMPATIBLE_VERSION)) { vogl_error_printf("%s: Trace file version is not supported, found version 0x%04X, expected at least version 0x%04X!\n", VOGL_FUNCTION_INFO_CSTR, m_sof_packet.m_version, VOGL_TRACE_FILE_MINIMUM_COMPATIBLE_VERSION); return false; } else if (m_sof_packet.m_version > static_cast<uint16_t>(VOGL_TRACE_FILE_VERSION)) { // TODO: Make this an error? Backwards compat? vogl_warning_printf("%s: Trace file version is 0x%04X, expected version 0x%04X, this may not work at all!\n", VOGL_FUNCTION_INFO_CSTR, m_sof_packet.m_version, VOGL_TRACE_FILE_VERSION); } if (m_sof_packet.m_archive_size) { if (!m_archive_blob_manager.init_file(cBMFReadable | cBMFOpenExisting, pFilename, m_sof_packet.m_archive_offset, m_sof_packet.m_archive_size)) { vogl_error_printf("%s: Failed reading in-trace archive!\n", VOGL_FUNCTION_INFO_CSTR); return false; } } m_packet_buf.reserve(512 * 1024); m_trace_stream.seek(m_sof_packet.m_first_packet_offset, false); if (!read_frame_file_offsets()) { // Keep this in sync with the offset pushed in vogl_init_tracefile()! m_frame_file_offsets.push_back(get_cur_file_ofs()); } return true; }
// This helper only works on files with valid file sizes (i.e. it won't work on some files under proc such as /proc/self/status). bool file_utils::read_text_file(const char *pPath, dynamic_string_array &lines, uint32_t flags) { cfile_stream stream; if (!stream.open(pPath, cDataStreamReadable)) { if (flags & cRTFPrintErrorMessages) vogl_error_printf("Failed opening text file \"%s\" for reading\n", pPath); else if (flags & cRTFPrintWarningMessages) vogl_warning_printf("Failed opening text file \"%s\" for reading\n", pPath); return false; } int line_count = 0; dynamic_string line_str; while (stream.get_remaining()) { ++line_count; if (!stream.read_line(line_str)) { if (flags & cRTFPrintErrorMessages) vogl_error_printf("Failed reading from text file \"%s\"\n", pPath); else if (flags & cRTFPrintWarningMessages) vogl_warning_printf("Failed reading from text file \"%s\"\n", pPath); break; } if (flags & cRTFTrim) line_str.trim(); if (flags & cRTFTrimEnd) line_str.trim_end(); if (flags & cRTFIgnoreEmptyLines) { if (line_str.is_empty()) continue; } if ((flags & cRTFIgnoreCommentedLines) && (line_str.get_len() >= 2)) { bool found_comment = false; for (int i = 0; i < static_cast<int>(line_str.get_len()); ++i) { char c = line_str[i]; if ((c == ' ') || (c == '\t')) continue; else if ((c == '/') && (line_str[i + 1] == '/')) found_comment = true; break; } if (found_comment) continue; } lines.push_back(line_str); } return true; }
bool vogl_matrix_state::save_matrix_stack(const vogl_context_info &context_info, GLenum matrix, uint32_t index, GLenum depth_get, GLenum matrix_get) { VOGL_FUNC_TRACER VOGL_NOTE_UNUSED(context_info); GL_ENTRYPOINT(glMatrixMode)(matrix); if (vogl_check_gl_error()) return false; GLint depth = 0; GL_ENTRYPOINT(glGetIntegerv)(depth_get, &depth); if (vogl_check_gl_error()) { // This *should* work on AMD because it supports the ARB_imaging subset on compat contexts, and it supports the GL_COLOR matrix and the max stack depth is reported as 10. if (depth_get == GL_COLOR_MATRIX_STACK_DEPTH) { vogl_warning_printf("Using GL_COLOR_MATRIX_STACK_DEPTH workaround for AMD drivers - this will purposely force a stack underflow!\n"); vogl::vector<matrix44D> matrices; for (;;) { matrix44D mat; GL_ENTRYPOINT(glGetDoublev)(matrix_get, mat.get_ptr()); if (vogl_check_gl_error()) return false; matrices.push_back(mat); GL_ENTRYPOINT(glPopMatrix)(); bool failed_popping = vogl_check_gl_error(); GL_ENTRYPOINT(glGetDoublev)(matrix_get, mat.get_ptr()); // AMD fails with a stack underflow on the get, not the pop - at least during tracing? if (vogl_check_gl_error()) failed_popping = true; if (failed_popping) break; } for (int i = matrices.size() - 1; i >= 0; i--) { if (i != static_cast<int>(matrices.size()) - 1) { GL_ENTRYPOINT(glPushMatrix)(); if (vogl_check_gl_error()) return false; } GL_ENTRYPOINT(glLoadMatrixd)(matrices[i].get_ptr()); if (vogl_check_gl_error()) return false; } depth = matrices.size(); } else { return false; } } if (depth < 1) return false; matrix_vec &vec = m_matrices[matrix_key(matrix, index)]; vec.resize(depth); // deepest .. current // 0 1 2 for (int i = 0; i < depth; i++) { matrix44D mat; GL_ENTRYPOINT(glGetDoublev)(matrix_get, mat.get_ptr()); if (vogl_check_gl_error()) return false; vec[depth - 1 - i] = mat; if (i != (depth - 1)) { GL_ENTRYPOINT(glPopMatrix)(); if (vogl_check_gl_error()) return false; } } for (int i = 1; i < depth; i++) { GL_ENTRYPOINT(glPushMatrix)(); if (vogl_check_gl_error()) return false; GL_ENTRYPOINT(glLoadMatrixd)(vec[i].get_ptr()); if (vogl_check_gl_error()) return false; } return true; }
//---------------------------------------------------------------------------------------------------------------------- // vogl_devel_dump_internal_texture_formats // This func is only for testing various internal GL format related API's // This func is used to generate vogl_internal_texture_formats.inc //---------------------------------------------------------------------------------------------------------------------- void vogl_devel_dump_internal_texture_formats(const vogl_context_info &context_info) { VOGL_FUNC_TRACER VOGL_CHECK_GL_ERROR; vogl_scoped_binding_state orig_texture; orig_texture.save_textures(&context_info); vogl_scoped_state_saver state_saver(cGSTPixelStore, cGSTPixelTransfer); vogl_reset_pixel_store_states(); vogl_reset_pixel_transfer_states(context_info); #if 0 // silly experiment { GLuint handle; ACTUAL_GL_ENTRYPOINT(glGenTextures)(1, &handle); VOGL_CHECK_GL_ERROR; ACTUAL_GL_ENTRYPOINT(glBindTexture)(GL_TEXTURE_2D, handle); VOGL_CHECK_GL_ERROR; for (uint32_t i = 0; i < 256; i++) { uint8_t vals[4] = { i, 0, 0, 0 }; //ACTUAL_GL_ENTRYPOINT(glTexImage2D)(GL_TEXTURE_2D, 0, GL_R8_SNORM, 1, 1, 0, GL_RED, GL_BYTE, vals); //float vals[1] = { ( i - 128.0f) / 127.0f }; //float vals[1] = { i / 255.0f }; //ACTUAL_GL_ENTRYPOINT(glPixelTransferf)(GL_RED_SCALE, .5f); //ACTUAL_GL_ENTRYPOINT(glPixelTransferf)(GL_RED_BIAS, 0.5f); ACTUAL_GL_ENTRYPOINT(glTexImage2D)(GL_TEXTURE_2D, 0, GL_RGB8UI, 1, 1, 0, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, vals); //ACTUAL_GL_ENTRYPOINT(glPixelTransferf)(GL_RED_SCALE, 1.0f); //ACTUAL_GL_ENTRYPOINT(glPixelTransferf)(GL_RED_BIAS, 0.0f); VOGL_CHECK_GL_ERROR; uint16_t gvals[4] = { 0, 0, 0, 0 }; ACTUAL_GL_ENTRYPOINT(glGetTexImage)(GL_TEXTURE_2D, 0, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, gvals); VOGL_CHECK_GL_ERROR; printf("%u %u %u %u, %u %u %u %u\n", vals[0], vals[1], vals[2], vals[3], gvals[0], gvals[1], gvals[2], gvals[3]); } ACTUAL_GL_ENTRYPOINT(glDeleteTextures)(1, &handle); } #endif typedef vogl::map<GLenum, vogl_internal_tex_format> tex_format_map; tex_format_map internal_formats; // Iterate through the base internal fmts, which need some special handling (argh) because the actual internal fmt != the requested internal fmt GLenum base_internal_formats[] = { GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL, GL_ALPHA, GL_RED, GL_RG, GL_RGB, GL_RGBA, GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_INTENSITY, GL_SLUMINANCE, GL_SLUMINANCE_ALPHA, GL_SRGB, GL_SRGB_ALPHA }; for (uint32_t i = 0; i < VOGL_ARRAY_SIZE(base_internal_formats); i++) { printf("%s\n", get_gl_enums().find_gl_name(base_internal_formats[i])); GLuint handle; GL_ENTRYPOINT(glGenTextures)(1, &handle); VOGL_CHECK_GL_ERROR; GLenum target = GL_TEXTURE_2D; GL_ENTRYPOINT(glBindTexture)(target, handle); GLenum base_internal_fmt = base_internal_formats[i]; vogl_internal_tex_format f; GL_ENTRYPOINT(glGetInternalformativ)(target, base_internal_fmt, GL_GET_TEXTURE_IMAGE_TYPE, sizeof(f.m_optimum_get_image_type), (GLint *)&f.m_optimum_get_image_type); GL_ENTRYPOINT(glGetInternalformativ)(target, base_internal_fmt, GL_GET_TEXTURE_IMAGE_FORMAT, sizeof(f.m_optimum_get_image_fmt), (GLint *)&f.m_optimum_get_image_fmt); VOGL_CHECK_GL_ERROR; GLenum &get_fmt = f.m_optimum_get_image_fmt; GLenum &get_type = f.m_optimum_get_image_type; // manual fixups, ARGH switch (base_internal_fmt) { case GL_DEPTH_COMPONENT: { get_fmt = GL_DEPTH_COMPONENT; get_type = GL_FLOAT; break; } case GL_RG: { get_fmt = GL_RG; get_type = GL_UNSIGNED_BYTE; break; } case GL_RGB: { get_fmt = GL_RGB; get_type = GL_UNSIGNED_BYTE; break; } case GL_RED: { get_fmt = GL_RED; get_type = GL_UNSIGNED_BYTE; break; } case GL_COMPRESSED_LUMINANCE: { get_fmt = GL_LUMINANCE; get_type = GL_UNSIGNED_BYTE; break; } case GL_COMPRESSED_LUMINANCE_ALPHA: { get_fmt = GL_LUMINANCE_ALPHA; get_type = GL_UNSIGNED_BYTE; break; } case GL_COMPRESSED_RGB: { get_fmt = GL_RGBA; get_type = GL_UNSIGNED_BYTE; break; } case GL_COMPRESSED_RGBA: { get_fmt = GL_RGBA; get_type = GL_UNSIGNED_BYTE; break; } case GL_LUMINANCE_ALPHA: { get_fmt = GL_LUMINANCE_ALPHA; get_type = GL_UNSIGNED_BYTE; break; } case GL_SLUMINANCE_ALPHA: { get_fmt = GL_LUMINANCE_ALPHA; get_type = GL_UNSIGNED_BYTE; break; } case GL_SRGB: { get_fmt = GL_RGB; get_type = GL_UNSIGNED_BYTE; break; } case GL_SRGB_ALPHA: { get_fmt = GL_RGBA; get_type = GL_UNSIGNED_BYTE; break; } default: { break; } } VOGL_VERIFY(get_fmt != GL_NONE); VOGL_VERIFY(get_type != GL_NONE); GL_ENTRYPOINT(glTexImage2D)(target, 0, base_internal_fmt, 32, 32, 0, get_fmt, get_type, NULL); VOGL_VERIFY(!vogl_check_gl_error()); //bool any_gl_errors = false; #define GET_INT(dst, gl_enum) \ do \ { \ int values[4]; \ utils::zero_object(values); \ GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, 0, (gl_enum), values); \ (dst) = values[0]; \ } while (0) #define GET_BOOL(dst, gl_enum) \ do \ { \ int values[4]; \ utils::zero_object(values); \ GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, 0, (gl_enum), values); \ (dst) = values[0] != 0; \ } while (0) GLenum actual_internal_fmt; GET_INT(actual_internal_fmt, GL_TEXTURE_INTERNAL_FORMAT); f.m_tex_image_flags = ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4)); f.m_fmt = base_internal_fmt; f.m_actual_internal_fmt = actual_internal_fmt; f.m_name = get_gl_enums().find_name(base_internal_fmt, "gl"); GET_INT(f.m_comp_sizes[cTCRed], GL_TEXTURE_RED_SIZE); GET_INT(f.m_comp_sizes[cTCGreen], GL_TEXTURE_GREEN_SIZE); GET_INT(f.m_comp_sizes[cTCBlue], GL_TEXTURE_BLUE_SIZE); GET_INT(f.m_comp_sizes[cTCAlpha], GL_TEXTURE_ALPHA_SIZE); GET_INT(f.m_comp_sizes[cTCStencil], GL_TEXTURE_STENCIL_SIZE); GET_INT(f.m_comp_sizes[cTCDepth], GL_TEXTURE_DEPTH_SIZE); GET_INT(f.m_comp_sizes[cTCIntensity], GL_TEXTURE_INTENSITY_SIZE); GET_INT(f.m_comp_sizes[cTCLuminance], GL_TEXTURE_LUMINANCE_SIZE); GET_INT(f.m_comp_types[cTCRed], GL_TEXTURE_RED_TYPE); GET_INT(f.m_comp_types[cTCGreen], GL_TEXTURE_GREEN_TYPE); GET_INT(f.m_comp_types[cTCBlue], GL_TEXTURE_BLUE_TYPE); GET_INT(f.m_comp_types[cTCAlpha], GL_TEXTURE_ALPHA_TYPE); GET_INT(f.m_comp_types[cTCDepth], GL_TEXTURE_DEPTH_TYPE); GET_INT(f.m_comp_types[cTCIntensity], GL_TEXTURE_INTENSITY_TYPE); GET_INT(f.m_comp_types[cTCLuminance], GL_TEXTURE_LUMINANCE_TYPE); GET_INT(f.m_shared_size, GL_TEXTURE_SHARED_SIZE); GET_BOOL(f.m_compressed, GL_TEXTURE_COMPRESSED); printf("base_internal_fmt: %s get_fmt: %s get_type: %s, actual_internal_fmt: %s compressed: %u\n", get_gl_enums().find_gl_name(base_internal_fmt), get_gl_enums().find_gl_name(get_fmt), get_gl_enums().find_gl_name(get_type), get_gl_enums().find_gl_name(actual_internal_fmt), f.m_compressed); #undef GET_INT #undef GET_BOOL //VOGL_ASSERT(!any_gl_errors); VOGL_ASSERT(f.m_actual_internal_fmt != GL_NONE); VOGL_ASSERT(f.m_optimum_get_image_fmt != GL_NONE); VOGL_ASSERT(f.m_optimum_get_image_type != GL_NONE); VOGL_ASSERT(!f.m_compressed); VOGL_ASSERT(!ktx_is_compressed_ogl_fmt(f.m_fmt) && !ktx_is_compressed_ogl_fmt(f.m_actual_internal_fmt)); VOGL_ASSERT(ktx_get_ogl_compressed_base_internal_fmt(f.m_fmt) == 0 && ktx_get_ogl_compressed_base_internal_fmt(f.m_actual_internal_fmt) == 0); if (!internal_formats.insert(base_internal_fmt, f).second) { internal_formats.find_value(base_internal_fmt)->m_tex_image_flags |= ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4)); } GL_ENTRYPOINT(glBindTexture)(target, 0); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glDeleteTextures)(1, &handle); VOGL_CHECK_GL_ERROR; } for (uint32_t t = 0; t < 5; t++) { GLenum target = GL_NONE; switch (t) { case 0: { target = GL_TEXTURE_1D; break; } case 1: { target = GL_TEXTURE_2D; break; } case 2: { target = GL_TEXTURE_3D; break; } case 3: { target = GL_TEXTURE_2D_MULTISAMPLE; break; } case 4: { target = GL_TEXTURE_2D_MULTISAMPLE_ARRAY; break; } default: { VOGL_ASSERT_ALWAYS; break; } } for (uint32_t fmt = 0; fmt <= 0xFFFF; fmt++) { GLuint handle; GL_ENTRYPOINT(glGenTextures)(1, &handle); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glBindTexture)(target, handle); vogl_debug_message_control(context_info, GL_INVALID_ENUM, false); vogl_debug_message_control(context_info, GL_INVALID_OPERATION, false); bool failed = false; switch (t) { case 0: { GL_ENTRYPOINT(glTexStorage1D)(target, 1, fmt, 32); failed = vogl_check_gl_error_suppress_message(); break; } case 1: { GL_ENTRYPOINT(glTexStorage2D)(target, 1, fmt, 32, 32); failed = vogl_check_gl_error_suppress_message(); break; } case 2: { GL_ENTRYPOINT(glTexStorage3D)(target, 1, fmt, 32, 32, 32); failed = vogl_check_gl_error_suppress_message(); break; } case 3: { GL_ENTRYPOINT(glTexStorage2DMultisample)(target, 2, fmt, 32, 32, GL_TRUE); failed = vogl_check_gl_error_suppress_message(); break; } case 4: { GL_ENTRYPOINT(glTexStorage3DMultisample)(target, 2, fmt, 32, 32, 2, GL_TRUE); failed = vogl_check_gl_error_suppress_message(); break; } } vogl_debug_message_control(context_info, GL_INVALID_ENUM, true); vogl_debug_message_control(context_info, GL_INVALID_OPERATION, true); if (failed) continue; bool any_gl_errors = false; VOGL_NOTE_UNUSED(any_gl_errors); vogl_internal_tex_format f; f.m_tex_image_flags = (1 << t); f.m_fmt = fmt; f.m_actual_internal_fmt = fmt; // this assumes the actual internal fmt will match here! f.m_name = get_gl_enums().find_name(fmt, "gl"); #define GET_INT(dst, gl_enum) \ do \ { \ int values[4]; \ utils::zero_object(values); \ GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, 0, (gl_enum), values); \ (dst) = values[0]; \ } while (0) #define GET_BOOL(dst, gl_enum) \ do \ { \ int values[4]; \ utils::zero_object(values); \ GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, 0, (gl_enum), values); \ (dst) = values[0] != 0; \ } while (0) GLenum internal_fmt; GET_INT(internal_fmt, GL_TEXTURE_INTERNAL_FORMAT); VOGL_ASSERT(internal_fmt == fmt); GET_INT(f.m_comp_sizes[cTCRed], GL_TEXTURE_RED_SIZE); GET_INT(f.m_comp_sizes[cTCGreen], GL_TEXTURE_GREEN_SIZE); GET_INT(f.m_comp_sizes[cTCBlue], GL_TEXTURE_BLUE_SIZE); GET_INT(f.m_comp_sizes[cTCAlpha], GL_TEXTURE_ALPHA_SIZE); GET_INT(f.m_comp_sizes[cTCStencil], GL_TEXTURE_STENCIL_SIZE); GET_INT(f.m_comp_sizes[cTCDepth], GL_TEXTURE_DEPTH_SIZE); GET_INT(f.m_comp_sizes[cTCIntensity], GL_TEXTURE_INTENSITY_SIZE); GET_INT(f.m_comp_sizes[cTCLuminance], GL_TEXTURE_LUMINANCE_SIZE); GET_INT(f.m_comp_types[cTCRed], GL_TEXTURE_RED_TYPE); GET_INT(f.m_comp_types[cTCGreen], GL_TEXTURE_GREEN_TYPE); GET_INT(f.m_comp_types[cTCBlue], GL_TEXTURE_BLUE_TYPE); GET_INT(f.m_comp_types[cTCAlpha], GL_TEXTURE_ALPHA_TYPE); GET_INT(f.m_comp_types[cTCDepth], GL_TEXTURE_DEPTH_TYPE); GET_INT(f.m_comp_types[cTCIntensity], GL_TEXTURE_INTENSITY_TYPE); GET_INT(f.m_comp_types[cTCLuminance], GL_TEXTURE_LUMINANCE_TYPE); GET_INT(f.m_shared_size, GL_TEXTURE_SHARED_SIZE); GET_BOOL(f.m_compressed, GL_TEXTURE_COMPRESSED); #undef GET_INT #undef GET_BOOL VOGL_ASSERT(!any_gl_errors); GL_ENTRYPOINT(glGetInternalformativ)(target, fmt, GL_GET_TEXTURE_IMAGE_TYPE, sizeof(f.m_optimum_get_image_type), (GLint *)&f.m_optimum_get_image_type); GL_ENTRYPOINT(glGetInternalformativ)(target, fmt, GL_GET_TEXTURE_IMAGE_FORMAT, sizeof(f.m_optimum_get_image_fmt), (GLint *)&f.m_optimum_get_image_fmt); VOGL_CHECK_GL_ERROR; if (f.m_compressed) { f.m_optimum_get_image_fmt = GL_RGBA; f.m_optimum_get_image_type = GL_UNSIGNED_BYTE; } else { #define HANDLE_FMT(gl_enum, fmt, type) \ case gl_enum: \ { \ f.m_optimum_get_image_fmt = fmt; \ f.m_optimum_get_image_type = type; \ break; \ } bool unhandled = false; switch (fmt) { HANDLE_FMT(GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV); HANDLE_FMT(GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV); HANDLE_FMT(GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT); HANDLE_FMT(GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT); HANDLE_FMT(GL_INTENSITY32F_ARB, GL_RED, GL_FLOAT); HANDLE_FMT(2, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE); HANDLE_FMT(3, GL_RGB, GL_UNSIGNED_BYTE); HANDLE_FMT(GL_LUMINANCE4_ALPHA4, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE); HANDLE_FMT(GL_LUMINANCE6_ALPHA2, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE); HANDLE_FMT(GL_LUMINANCE8_ALPHA8, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE); HANDLE_FMT(GL_LUMINANCE12_ALPHA4, GL_LUMINANCE_ALPHA, GL_UNSIGNED_SHORT); HANDLE_FMT(GL_LUMINANCE12_ALPHA12, GL_LUMINANCE_ALPHA, GL_UNSIGNED_SHORT); HANDLE_FMT(GL_LUMINANCE16_ALPHA16, GL_LUMINANCE_ALPHA, GL_UNSIGNED_SHORT); HANDLE_FMT(GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE); HANDLE_FMT(GL_RGB8I, GL_RGB_INTEGER, GL_BYTE); HANDLE_FMT(GL_RGB10, GL_RGB, GL_UNSIGNED_SHORT); HANDLE_FMT(GL_RGB12, GL_RGB, GL_UNSIGNED_SHORT); HANDLE_FMT(GL_RGB16, GL_RGB, GL_UNSIGNED_SHORT); HANDLE_FMT(GL_RGBA12, GL_RGB, GL_UNSIGNED_SHORT); HANDLE_FMT(GL_RG8, GL_RG, GL_UNSIGNED_BYTE); HANDLE_FMT(GL_RG16, GL_RG, GL_UNSIGNED_SHORT); HANDLE_FMT(GL_RG16F, GL_RG, GL_HALF_FLOAT); HANDLE_FMT(GL_RG32F, GL_RG, GL_FLOAT); HANDLE_FMT(GL_SRGB8, GL_RGB, GL_UNSIGNED_BYTE); HANDLE_FMT(GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE); HANDLE_FMT(GL_SLUMINANCE8_ALPHA8, GL_LUMINANCE_ALPHA, GL_BYTE); HANDLE_FMT(GL_RGB32I, GL_RGB_INTEGER, GL_INT); HANDLE_FMT(GL_RGB16I, GL_RGB_INTEGER, GL_SHORT); HANDLE_FMT(GL_RGB32UI, GL_RGB_INTEGER, GL_UNSIGNED_INT); HANDLE_FMT(GL_RGB16UI, GL_RGB_INTEGER, GL_UNSIGNED_SHORT); HANDLE_FMT(GL_RGB8UI, GL_RGB_INTEGER, GL_UNSIGNED_INT); HANDLE_FMT(GL_SIGNED_RGBA8_NV, GL_RGBA, GL_BYTE); HANDLE_FMT(GL_SIGNED_RGB8_NV, GL_RGB, GL_BYTE); HANDLE_FMT(GL_SIGNED_LUMINANCE8_ALPHA8_NV, GL_LUMINANCE_ALPHA, GL_BYTE); HANDLE_FMT(GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV, GL_RGBA, GL_BYTE); HANDLE_FMT(GL_RG8_SNORM, GL_RG, GL_BYTE); HANDLE_FMT(GL_RGB8_SNORM, GL_RGB, GL_BYTE); HANDLE_FMT(GL_RG16_SNORM, GL_RG, GL_SHORT); HANDLE_FMT(GL_RGB16_SNORM, GL_RGB, GL_SHORT); HANDLE_FMT(GL_RGB32F, GL_RGB, GL_FLOAT); HANDLE_FMT(GL_RGB16F, GL_RGB, GL_HALF_FLOAT); // TODO: Research oddball formats HANDLE_FMT(GL_PALETTE4_RGB8_OES, GL_RGB, GL_UNSIGNED_BYTE); HANDLE_FMT(GL_PALETTE4_R5_G6_B5_OES, GL_RGB, GL_UNSIGNED_BYTE); HANDLE_FMT(GL_PALETTE8_RGB8_OES, GL_RGB, GL_UNSIGNED_BYTE); HANDLE_FMT(GL_PALETTE8_R5_G6_B5_OES, GL_RGB, GL_UNSIGNED_BYTE); HANDLE_FMT(GL_HILO16_NV, GL_NONE, GL_NONE); HANDLE_FMT(GL_SIGNED_HILO16_NV, GL_NONE, GL_NONE); HANDLE_FMT(GL_DSDT8_MAG8_INTENSITY8_NV, GL_NONE, GL_NONE); HANDLE_FMT(GL_HILO8_NV, GL_NONE, GL_NONE); HANDLE_FMT(GL_SIGNED_HILO8_NV, GL_NONE, GL_NONE); HANDLE_FMT(GL_DSDT8_NV, GL_NONE, GL_NONE); HANDLE_FMT(GL_DSDT8_MAG8_NV, GL_NONE, GL_NONE); default: unhandled = true; break; } if ((unhandled) && ((f.m_optimum_get_image_fmt == GL_NONE) || (f.m_optimum_get_image_type == GL_NONE))) { printf("INVALID: %s %s %s\n", f.m_name.get_ptr(), get_gl_enums().find_name(f.m_optimum_get_image_fmt, "gl"), get_gl_enums().find_name(f.m_optimum_get_image_type, "gl")); } } #undef HANDLE_FMT VOGL_ASSERT(f.m_actual_internal_fmt != GL_NONE); if ((f.m_optimum_get_image_fmt == GL_NONE) || (f.m_optimum_get_image_type == GL_NONE)) vogl_warning_printf("Don't have an optimal get format/type for internal format %s\n", get_gl_enums().find_gl_name(fmt)); VOGL_ASSERT(fmt != GL_LUMINANCE); VOGL_ASSERT(f.m_fmt == f.m_actual_internal_fmt); if (!f.m_compressed) { VOGL_ASSERT(!ktx_is_compressed_ogl_fmt(f.m_fmt) && !ktx_is_compressed_ogl_fmt(f.m_actual_internal_fmt)); VOGL_ASSERT(ktx_get_ogl_compressed_base_internal_fmt(f.m_fmt) == 0 && ktx_get_ogl_compressed_base_internal_fmt(f.m_actual_internal_fmt) == 0); } else { VOGL_ASSERT(ktx_is_compressed_ogl_fmt(f.m_actual_internal_fmt)); VOGL_ASSERT(ktx_get_ogl_compressed_base_internal_fmt(f.m_actual_internal_fmt) != 0); } if (!internal_formats.insert(fmt, f).second) { internal_formats.find_value(fmt)->m_tex_image_flags |= (1 << t); } GL_ENTRYPOINT(glBindTexture)(target, 0); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glDeleteTextures)(1, &handle); VOGL_CHECK_GL_ERROR; } } const char *pOutput_filename = "internal_texture_formats.inc"; FILE *pFile = vogl_fopen(pOutput_filename, "w"); VOGL_VERIFY(pFile); if (!pFile) return; for (tex_format_map::const_iterator it = internal_formats.begin(); it != internal_formats.end(); ++it) { vogl_internal_tex_format fmt(it->second); uint32_t actual_size = 0; if (!fmt.m_compressed) { VOGL_ASSERT(!ktx_is_compressed_ogl_fmt(fmt.m_fmt)); VOGL_ASSERT(ktx_get_ogl_compressed_base_internal_fmt(fmt.m_fmt) == 0); } else { VOGL_ASSERT(ktx_is_compressed_ogl_fmt(fmt.m_fmt)); VOGL_ASSERT(ktx_get_ogl_compressed_base_internal_fmt(fmt.m_fmt) != 0); } if ((!fmt.m_compressed) && (fmt.m_optimum_get_image_fmt != GL_NONE) && (fmt.m_optimum_get_image_type != GL_NONE)) { GLuint handle; GL_ENTRYPOINT(glGenTextures)(1, &handle); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glBindTexture)(GL_TEXTURE_2D, handle); VOGL_CHECK_GL_ERROR; uint8_t vals[128]; utils::zero_object(vals); vals[1] = 64; GL_ENTRYPOINT(glTexImage2D)(GL_TEXTURE_2D, 0, fmt.m_fmt, 1, 1, 0, fmt.m_optimum_get_image_fmt, fmt.m_optimum_get_image_type, vals); if (vogl_check_gl_error()) { printf("glTexImage2D FAILED: %s %s %s\n", fmt.m_name.get_ptr(), get_gl_enums().find_name(fmt.m_optimum_get_image_fmt, "gl"), get_gl_enums().find_name(fmt.m_optimum_get_image_type, "gl")); } uint8_t gvals[128]; memset(gvals, 0xCD, sizeof(gvals)); GL_ENTRYPOINT(glGetTexImage)(GL_TEXTURE_2D, 0, fmt.m_optimum_get_image_fmt, fmt.m_optimum_get_image_type, gvals); uint32_t actual_size0 = 0; for (actual_size0 = 0; actual_size0 < sizeof(gvals); actual_size0++) if (gvals[actual_size0] == 0xCD) break; memset(gvals, 0x12, sizeof(gvals)); GL_ENTRYPOINT(glGetTexImage)(GL_TEXTURE_2D, 0, fmt.m_optimum_get_image_fmt, fmt.m_optimum_get_image_type, gvals); uint32_t actual_size1 = 0; for (actual_size1 = 0; actual_size1 < sizeof(gvals); actual_size1++) if (gvals[actual_size1] == 0x12) break; VOGL_VERIFY(actual_size0 == actual_size1); //printf("glGetTexImage() wrote %u bytes\n", actual_size0); if (vogl_check_gl_error()) // || gvals[1] != vals[1]) { printf("glGetTexImage() failed: %s %s %s\n", fmt.m_name.get_ptr(), get_gl_enums().find_name(fmt.m_optimum_get_image_fmt, "gl"), get_gl_enums().find_name(fmt.m_optimum_get_image_type, "gl")); } GL_ENTRYPOINT(glBindTexture)(GL_TEXTURE_2D, 0); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glDeleteTextures)(1, &handle); actual_size = actual_size0; uint32_t s = vogl_get_image_format_size_in_bytes(fmt.m_optimum_get_image_fmt, fmt.m_optimum_get_image_type); VOGL_VERIFY(s); if (s != actual_size0) { VOGL_VERIFY(0); } vogl::ktx_texture ktx_tex; GLenum img_fmt; GLenum img_type; img_fmt = fmt.m_optimum_get_image_fmt; img_type = fmt.m_optimum_get_image_type; uint32_t block_dim, bytes_per_block; bool success = ktx_get_ogl_fmt_desc(img_fmt, img_type, block_dim, bytes_per_block); VOGL_VERIFY(success); VOGL_VERIFY(block_dim == 1); VOGL_VERIFY(bytes_per_block == actual_size); if (!ktx_tex.init_2D(1, 1, 1, fmt.m_fmt, img_fmt, img_type)) { printf("ktx_texture::init_2D() failed: %s %s %s\n", fmt.m_name.get_ptr(), get_gl_enums().find_name(fmt.m_optimum_get_image_fmt, "gl"), get_gl_enums().find_name(fmt.m_optimum_get_image_type, "gl")); } } else if (fmt.m_compressed) { GLuint handle; GL_ENTRYPOINT(glGenTextures)(1, &handle); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glBindTexture)(GL_TEXTURE_2D, handle); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glTexStorage2D)(GL_TEXTURE_2D, 1, fmt.m_fmt, 1, 1); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glGetTexLevelParameteriv)(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, (GLint *)&actual_size); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glBindTexture)(GL_TEXTURE_2D, 0); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glDeleteTextures)(1, &handle); VOGL_CHECK_GL_ERROR; uint32_t block_width = 0, block_height = 0, block_size = 0; GL_ENTRYPOINT(glGetInternalformativ)(GL_TEXTURE_2D, fmt.m_fmt, GL_TEXTURE_COMPRESSED_BLOCK_WIDTH, sizeof(int), reinterpret_cast<GLint *>(&block_width)); GL_ENTRYPOINT(glGetInternalformativ)(GL_TEXTURE_2D, fmt.m_fmt, GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT, sizeof(int), reinterpret_cast<GLint *>(&block_height)); GL_ENTRYPOINT(glGetInternalformativ)(GL_TEXTURE_2D, fmt.m_fmt, GL_TEXTURE_COMPRESSED_BLOCK_SIZE, sizeof(int), reinterpret_cast<GLint *>(&block_size)); VOGL_CHECK_GL_ERROR; if (block_size == actual_size * 8U) block_size /= 8; uint32_t block_dim, bytes_per_block; bool success = ktx_get_ogl_fmt_desc(fmt.m_fmt, GL_UNSIGNED_BYTE, block_dim, bytes_per_block); if ((!success) || (block_dim != block_width) || (block_dim != block_height) || (bytes_per_block != actual_size) || (bytes_per_block != block_size)) { printf("ktx_get_ogl_fmt_desc on compressed format failed: %s %s %s %u %i %i %i\n", fmt.m_name.get_ptr(), get_gl_enums().find_name(fmt.m_optimum_get_image_fmt, "gl"), get_gl_enums().find_name(fmt.m_optimum_get_image_type, "gl"), actual_size, block_width, block_height, block_size); } fmt.m_block_width = block_width; fmt.m_block_height = block_height; vogl::ktx_texture ktx_tex; if (!ktx_tex.init_2D(1, 1, 1, fmt.m_fmt, GL_NONE, GL_NONE)) { printf("ktx_texture::init_2D() compressed failed: %s %s %s\n", fmt.m_name.get_ptr(), get_gl_enums().find_name(fmt.m_optimum_get_image_fmt, "gl"), get_gl_enums().find_name(fmt.m_optimum_get_image_type, "gl")); } } fmt.m_image_bytes_per_pixel_or_block = actual_size; fprintf(pFile, " vogl_internal_tex_format(0x%04X, \"%s\", 0x%04X,\n", fmt.m_fmt, fmt.m_name.get_ptr(), fmt.m_actual_internal_fmt); fprintf(pFile, " "); for (uint32_t i = 0; i < cTCTotalComponents; i++) fprintf(pFile, "%u, ", fmt.m_comp_sizes[i]); fprintf(pFile, "\n"); fprintf(pFile, " "); for (uint32_t i = 0; i < cTCTotalComponents; i++) fprintf(pFile, "%s, ", get_gl_enums().find_name(fmt.m_comp_types[i], "gl")); fprintf(pFile, "\n"); fprintf(pFile, " %u, 0x%02X, %u, \n", fmt.m_shared_size, fmt.m_tex_image_flags, fmt.m_compressed); fprintf(pFile, " %s, %s, %u, %u, %u),\n", get_gl_enums().find_name(fmt.m_optimum_get_image_fmt, "gl"), get_gl_enums().find_name(fmt.m_optimum_get_image_type, "gl"), fmt.m_image_bytes_per_pixel_or_block, fmt.m_block_width, fmt.m_block_height); #if 0 uint32_t tex_formats_count; static const vogl_internal_tex_format *tex_formats = get_vogl_internal_texture_formats(&tex_formats_count); for (uint32_t q = 0; q < tex_formats_count; q++) { if (tex_formats[q].m_fmt == fmt.m_fmt) { if (!tex_formats[q].compare(fmt)) { VOGL_ASSERT_ALWAYS; } break; } } if (q == tex_formats_count) { VOGL_ASSERT_ALWAYS; } #endif } vogl_fclose(pFile); printf("Wrote file %s\n", pOutput_filename); }
bool vogl_default_framebuffer_state::restore(const vogl_context_info &context_info, bool restore_front_buffer) const { VOGL_NOTE_UNUSED(context_info); if (!m_valid) return false; // TODO: Test multisampled default framebuffers // TODO: Check to ensure the stored fb is compatible with the current framebuffer const GLenum tex_target = (m_fb_attribs.m_samples > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D; vogl_scoped_state_saver framebuffer_state_saver(cGSTReadBuffer, cGSTDrawBuffer); vogl_scoped_binding_state orig_framebuffers(GL_DRAW_FRAMEBUFFER, GL_READ_FRAMEBUFFER, GL_TEXTURE_2D, GL_TEXTURE_2D_MULTISAMPLE); GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, 0); VOGL_CHECK_GL_ERROR; for (uint i = 0; i < cDefFramebufferTotal; i++) { if ((!restore_front_buffer) && ((i == cDefFramebufferFrontLeft) || (i == cDefFramebufferFrontRight))) continue; if (!m_textures[i].is_valid()) continue; GL_ENTRYPOINT(glDrawBuffer)((i == cDefFramebufferDepthStencil) ? GL_NONE : g_def_framebuffer_enums[i]); if (vogl_check_gl_error_internal(true)) continue; GLuint64 tex_handle64 = 0; vogl_handle_remapper def_handle_remapper; if (!m_textures[i].restore(context_info, def_handle_remapper, tex_handle64)) { vogl_error_printf("%s: Failed restoring texture %u\n", VOGL_METHOD_NAME, i); continue; } GLuint tex_handle = static_cast<GLuint>(tex_handle64); // Create FBO GLuint fbo_handle = 0; GL_ENTRYPOINT(glGenFramebuffers)(1, &fbo_handle); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glBindFramebuffer)(GL_READ_FRAMEBUFFER, fbo_handle); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glFramebufferTexture2D)(GL_READ_FRAMEBUFFER, (i == cDefFramebufferDepthStencil) ? GL_DEPTH_STENCIL_ATTACHMENT : GL_COLOR_ATTACHMENT0, tex_target, tex_handle, 0); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glReadBuffer)((i == cDefFramebufferDepthStencil) ? GL_NONE : GL_COLOR_ATTACHMENT0); VOGL_CHECK_GL_ERROR; GLenum cur_status = GL_ENTRYPOINT(glCheckFramebufferStatus)(GL_READ_FRAMEBUFFER); VOGL_CHECK_GL_ERROR; bool status = true; if (cur_status == GL_FRAMEBUFFER_COMPLETE) { GL_ENTRYPOINT(glBlitFramebuffer)( 0, 0, m_fb_attribs.m_width, m_fb_attribs.m_height, 0, 0, m_fb_attribs.m_width, m_fb_attribs.m_height, (i == cDefFramebufferDepthStencil) ? (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT) : GL_COLOR_BUFFER_BIT, GL_NEAREST); if (vogl_check_gl_error_internal()) { status = false; } } if (!status) { vogl_warning_printf("%s: Failed blitting framebuffer %u\n", VOGL_METHOD_NAME, i); } // Delete FBO GL_ENTRYPOINT(glBindFramebuffer)(GL_READ_FRAMEBUFFER, 0); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glDeleteFramebuffers)(1, &fbo_handle); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glReadBuffer)(GL_FRONT_LEFT); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glBindTexture)(tex_target, 0); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glDeleteTextures)(1, &tex_handle); VOGL_CHECK_GL_ERROR; } return true; }
bool vogl_default_framebuffer_state::snapshot(const vogl_context_info &context_info, const vogl_default_framebuffer_attribs &fb_attribs) { VOGL_NOTE_UNUSED(context_info); clear(); m_fb_attribs = fb_attribs; // Create compatible GL texture // Attach this texture to an FBO // Blit default framebuffer to this FBO // Capture this texture's state vogl_scoped_state_saver framebuffer_state_saver(cGSTReadBuffer, cGSTDrawBuffer); vogl_scoped_binding_state orig_framebuffers(GL_DRAW_FRAMEBUFFER, GL_READ_FRAMEBUFFER, GL_TEXTURE_2D, GL_TEXTURE_2D_MULTISAMPLE); GL_ENTRYPOINT(glBindFramebuffer)(GL_READ_FRAMEBUFFER, 0); VOGL_CHECK_GL_ERROR; vogl_scoped_binding_state orig_bindings(GL_PIXEL_PACK_BUFFER, GL_PIXEL_UNPACK_BUFFER); GL_ENTRYPOINT(glBindBuffer)(GL_PIXEL_PACK_BUFFER, 0); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glBindBuffer)(GL_PIXEL_UNPACK_BUFFER, 0); VOGL_CHECK_GL_ERROR; vogl_scoped_state_saver pixelstore_state_saver(cGSTPixelStore); vogl_scoped_state_saver pixeltransfer_state_saver; if (!context_info.is_core_profile()) pixeltransfer_state_saver.save(cGSTPixelTransfer); vogl_reset_pixel_store_states(); if (!context_info.is_core_profile()) vogl_reset_pixel_transfer_states(); // TODO: Test multisampled default framebuffers const GLenum tex_target = (fb_attribs.m_samples > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D; for (uint i = 0; i < cDefFramebufferTotal; i++) { GLenum internal_fmt, pixel_fmt, pixel_type; // TODO: This uses fixed pixel formats, and assumes there's always a depth/stencil buffer. if (i == cDefFramebufferDepthStencil) { if ((fb_attribs.m_depth_size + fb_attribs.m_stencil_size) == 0) continue; GL_ENTRYPOINT(glReadBuffer)(fb_attribs.m_double_buffered ? GL_BACK_LEFT : GL_FRONT_LEFT); internal_fmt = GL_DEPTH_STENCIL; pixel_fmt = GL_DEPTH_STENCIL; pixel_type = GL_UNSIGNED_INT_24_8; } else { if ((fb_attribs.m_r_size + fb_attribs.m_g_size + fb_attribs.m_b_size + fb_attribs.m_a_size) == 0) continue; GL_ENTRYPOINT(glReadBuffer)(g_def_framebuffer_enums[i]); internal_fmt = GL_RGBA; pixel_fmt = GL_RGBA; pixel_type = GL_UNSIGNED_INT_8_8_8_8_REV; } if (vogl_check_gl_error_internal(true)) continue; // Create texture GLuint tex_handle = 0; GL_ENTRYPOINT(glGenTextures)(1, &tex_handle); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glBindTexture)(tex_target, tex_handle); VOGL_CHECK_GL_ERROR; if (fb_attribs.m_samples > 1) { GL_ENTRYPOINT(glTexImage2DMultisample)(tex_target, fb_attribs.m_samples, internal_fmt, fb_attribs.m_width, fb_attribs.m_height, GL_TRUE); } else { GL_ENTRYPOINT(glTexImage2D)(tex_target, 0, internal_fmt, fb_attribs.m_width, fb_attribs.m_height, 0, pixel_fmt, pixel_type, NULL); } if (vogl_check_gl_error_internal()) { GL_ENTRYPOINT(glBindTexture)(tex_target, 0); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glDeleteTextures)(1, &tex_handle); VOGL_CHECK_GL_ERROR; continue; } GL_ENTRYPOINT(glTexParameteri)(tex_target, GL_TEXTURE_MAX_LEVEL, 0); VOGL_CHECK_GL_ERROR; // Create FBO GLuint fbo_handle = 0; GL_ENTRYPOINT(glGenFramebuffers)(1, &fbo_handle); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, fbo_handle); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glFramebufferTexture2D)(GL_DRAW_FRAMEBUFFER, (i == cDefFramebufferDepthStencil) ? GL_DEPTH_STENCIL_ATTACHMENT : GL_COLOR_ATTACHMENT0, tex_target, tex_handle, 0); VOGL_CHECK_GL_ERROR; GLenum draw_buf = (i == cDefFramebufferDepthStencil) ? GL_NONE : GL_COLOR_ATTACHMENT0; GL_ENTRYPOINT(glDrawBuffers)(1, &draw_buf); VOGL_CHECK_GL_ERROR; GLenum cur_status = GL_ENTRYPOINT(glCheckFramebufferStatus)(GL_DRAW_FRAMEBUFFER); VOGL_CHECK_GL_ERROR; bool status = true; if (cur_status == GL_FRAMEBUFFER_COMPLETE) { GL_ENTRYPOINT(glBlitFramebuffer)( 0, 0, fb_attribs.m_width, fb_attribs.m_height, 0, 0, fb_attribs.m_width, fb_attribs.m_height, (i == cDefFramebufferDepthStencil) ? (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT) : GL_COLOR_BUFFER_BIT, GL_NEAREST); if (vogl_check_gl_error_internal()) { status = false; } } if (status) { vogl_handle_remapper def_handle_remapper; status = m_textures[i].snapshot(context_info, def_handle_remapper, tex_handle, tex_target); if (!status) { vogl_error_printf("%s: Failed snapshotting texture for default framebuffer %s\n", VOGL_METHOD_NAME, g_gl_enums.find_gl_name(g_def_framebuffer_enums[i])); } } else { vogl_warning_printf("%s: Failed blitting framebuffer %u\n", VOGL_METHOD_NAME, i); } // Delete FBO GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, 0); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glDeleteFramebuffers)(1, &fbo_handle); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glDrawBuffer)(GL_FRONT_LEFT); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glBindTexture)(tex_target, 0); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glDeleteTextures)(1, &tex_handle); VOGL_CHECK_GL_ERROR; } m_valid = true; return true; }