bool vogl_matrix_state::restore_matrix_stack(const vogl_context_info &context_info, GLenum matrix, uint32_t index) const { VOGL_FUNC_TRACER VOGL_NOTE_UNUSED(context_info); const matrix_vec *pVec = m_matrices.find_value(matrix_key(matrix, index)); if ((!pVec) || (pVec->size() < 1)) return false; GL_ENTRYPOINT(glMatrixMode)(matrix); if (vogl_check_gl_error()) return false; // deepest .. current // 0 1 2 for (uint32_t i = 0; i < pVec->size(); i++) { if (i) { GL_ENTRYPOINT(glPushMatrix)(); if (vogl_check_gl_error()) return false; } GL_ENTRYPOINT(glLoadMatrixd)((*pVec)[i].get_ptr()); if (vogl_check_gl_error()) return false; } return true; }
bool vogl_matrix_state::snapshot(const vogl_context_info &context_info) { VOGL_FUNC_TRACER clear(); bool any_errors = false; VOGL_CHECK_GL_ERROR; vogl_scoped_state_saver state_saver(cGSTActiveTexture, cGSTMatrixMode); if (vogl_check_gl_error()) any_errors = true; if (!save_matrix_stack(context_info, GL_PROJECTION, 0, GL_PROJECTION_STACK_DEPTH, GL_PROJECTION_MATRIX)) any_errors = true; if (!save_matrix_stack(context_info, GL_MODELVIEW, 0, GL_MODELVIEW_STACK_DEPTH, GL_MODELVIEW_MATRIX)) any_errors = true; if (!save_matrix_stack(context_info, GL_COLOR, 0, GL_COLOR_MATRIX_STACK_DEPTH, GL_COLOR_MATRIX)) any_errors = true; for (uint32_t texcoord_index = 0; texcoord_index < context_info.get_max_texture_coords(); texcoord_index++) { GL_ENTRYPOINT(glActiveTexture)(GL_TEXTURE0 + texcoord_index); if (vogl_check_gl_error()) any_errors = true; if (!save_matrix_stack(context_info, GL_TEXTURE, texcoord_index, GL_TEXTURE_STACK_DEPTH, GL_TEXTURE_MATRIX)) any_errors = true; } for (uint32_t i = 0; i < context_info.get_max_arb_program_matrices(); i++) { if (!save_matrix_stack(context_info, GL_MATRIX0_ARB + i, 0, GL_CURRENT_MATRIX_STACK_DEPTH_ARB, GL_CURRENT_MATRIX_ARB)) any_errors = true; } if (any_errors) clear(); else m_valid = true; return !any_errors; }
bool vogl_material_state::restore(const vogl_context_info &context_info) const { VOGL_FUNC_TRACER VOGL_NOTE_UNUSED(context_info); if (!m_valid) { VOGL_ASSERT_ALWAYS; return false; } VOGL_CHECK_GL_ERROR; #define SET_FLOAT(side, pname) set_material_parameter(side, pname) for (uint s = 0; s < cTotalSides; s++) { SET_FLOAT(s, GL_AMBIENT); SET_FLOAT(s, GL_DIFFUSE); SET_FLOAT(s, GL_SPECULAR); SET_FLOAT(s, GL_EMISSION); SET_FLOAT(s, GL_SHININESS); SET_FLOAT(s, GL_COLOR_INDEXES); } #undef GET_FLOAT return !vogl_check_gl_error(); }
bool vogl_material_state::set_material_parameter(uint side, GLenum pname) const { VOGL_FUNC_TRACER const GLenum face = get_face(side); const vogl_state_data *pData = m_params[side].find(pname); if (!pData) { VOGL_ASSERT_ALWAYS; return false; } enum { cMaxElements = 4 }; if (pData->get_num_elements() > cMaxElements) { VOGL_ASSERT_ALWAYS; return false; } if ((pData->get_data_type() == cSTFloat) || (pData->get_data_type() == cSTDouble)) { float fvals[cMaxElements]; pData->get_float(fvals); if (pData->get_num_elements() == 1) GL_ENTRYPOINT(glMaterialf)(face, pname, fvals[0]); else GL_ENTRYPOINT(glMaterialfv)(face, pname, fvals); } else { int ivals[cMaxElements]; pData->get_int(ivals); if (pData->get_num_elements() == 1) GL_ENTRYPOINT(glMateriali)(face, pname, ivals[0]); else GL_ENTRYPOINT(glMaterialiv)(face, pname, ivals); } return !vogl_check_gl_error(); }
bool vogl_renderbuffer_desc::restore(const vogl_context_info &context_info) const { VOGL_FUNC_TRACER VOGL_NOTE_UNUSED(context_info); if (!m_width) return false; VOGL_ASSERT(context_info.get_version() >= VOGL_GL_VERSION_3_0); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glRenderbufferStorageMultisample)(GL_RENDERBUFFER, m_samples, m_internal_format, m_width, m_height); bool prev_gl_error = vogl_check_gl_error(); VOGL_ASSERT(!prev_gl_error); return !prev_gl_error; }
bool vogl_sampler_state::set_sampler_parameter(GLuint handle, GLenum pname) const { VOGL_FUNC_TRACER const vogl_state_data *pData = m_params.find(pname); if (!pData) return false; enum { cMaxElements = 16 }; if (pData->get_num_elements() > cMaxElements) { VOGL_ASSERT_ALWAYS; return false; } if ((pData->get_data_type() == cSTFloat) || (pData->get_data_type() == cSTDouble)) { float fvals[cMaxElements]; pData->get_float(fvals); if (pData->get_num_elements() == 1) GL_ENTRYPOINT(glSamplerParameterf)(handle, pname, fvals[0]); else GL_ENTRYPOINT(glSamplerParameterfv)(handle, pname, fvals); } else { int ivals[cMaxElements]; pData->get_int(ivals); if (pData->get_num_elements() == 1) GL_ENTRYPOINT(glSamplerParameteri)(handle, pname, ivals[0]); else GL_ENTRYPOINT(glSamplerParameteriv)(handle, pname, ivals); } return !vogl_check_gl_error(); }
bool vogl_query_state::snapshot(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 handle, GLenum target) { VOGL_FUNC_TRACER VOGL_NOTE_UNUSED(remapper); VOGL_CHECK_GL_ERROR; clear(); VOGL_ASSERT(handle <= cUINT32_MAX); m_snapshot_handle = static_cast<GLuint>(handle); m_target = target; m_has_been_begun = GL_ENTRYPOINT(glIsQuery)(static_cast<GLuint>(handle)) != 0; if (target != GL_NONE) { if (context_info.supports_extension("GL_ARB_timer_query") && GL_ENTRYPOINT(glGetQueryObjecti64v)) { GLint64 result = 0; GL_ENTRYPOINT(glGetQueryObjecti64v)(m_snapshot_handle, GL_QUERY_RESULT, &result); m_prev_result = result; } else { GLuint prev_result32; GL_ENTRYPOINT(glGetQueryObjectuiv)(m_snapshot_handle, GL_QUERY_RESULT, &prev_result32); m_prev_result = prev_result32; } } m_get_result_status = vogl_check_gl_error(); m_is_valid = true; return true; }
bool vogl_sync_state::restore(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 &handle) const { VOGL_FUNC_TRACER VOGL_NOTE_UNUSED(context_info); if (!m_is_valid) return false; VOGL_CHECK_GL_ERROR; if (!handle) { GLsync sync = GL_ENTRYPOINT(glFenceSync)(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); if ((vogl_check_gl_error()) || (!sync)) return false; handle = vogl_sync_to_handle(sync); remapper.declare_handle(VOGL_NAMESPACE_SYNCS, m_snapshot_handle, handle, GL_NONE); VOGL_ASSERT(remapper.remap_handle(VOGL_NAMESPACE_SYNCS, m_snapshot_handle) == handle); } return true; }
// One multisampled source, multiple non-multisampled destinations created by method. bool vogl_msaa_texture_splitter::split(GLenum src_target, GLuint src_texture, vogl::vector<GLuint> &dest_textures) { dest_textures.resize(0); if (!m_valid) return false; if ((src_target != GL_TEXTURE_2D_MULTISAMPLE) && (src_target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY)) return false; GLenum dest_target = (src_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D; GL_ENTRYPOINT(glBindTexture)(src_target, src_texture); VOGL_CHECK_GL_ERROR; GLint mip_level = 0, base_level = 0, max_level = 0; GLenum internal_fmt = 0; int base_width = 0, base_height = 0, base_depth = 0, samples = 0; GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, base_level, GL_TEXTURE_INTERNAL_FORMAT, reinterpret_cast<GLint *>(&internal_fmt)); GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, base_level, GL_TEXTURE_WIDTH, &base_width); GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, base_level, GL_TEXTURE_HEIGHT, &base_height); GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, base_level, GL_TEXTURE_DEPTH, &base_depth); GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, base_level, GL_TEXTURE_SAMPLES, &samples); VOGL_CHECK_GL_ERROR; if ((base_width < 1) || (base_height < 1) || (base_depth < 1) || (samples < 1)) return false; const vogl_internal_tex_format *pInternal_tex_fmt = vogl_find_internal_texture_format(internal_fmt); if ((!pInternal_tex_fmt) || (pInternal_tex_fmt->m_optimum_get_image_fmt == GL_NONE) || (pInternal_tex_fmt->m_optimum_get_image_type == GL_NONE)) return false; GLenum attachment_target = GL_COLOR_ATTACHMENT0; if ((pInternal_tex_fmt->m_comp_sizes[cTCDepth]) && (pInternal_tex_fmt->m_comp_sizes[cTCStencil])) attachment_target = GL_DEPTH_STENCIL_ATTACHMENT; else if (pInternal_tex_fmt->m_comp_sizes[cTCDepth]) attachment_target = GL_DEPTH_ATTACHMENT; else if (pInternal_tex_fmt->m_comp_sizes[cTCStencil]) return false; if (attachment_target == GL_COLOR_ATTACHMENT0) { GL_ENTRYPOINT(glDepthMask)(GL_FALSE); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glDisable)(GL_DEPTH_TEST); VOGL_CHECK_GL_ERROR; } else { GL_ENTRYPOINT(glDepthMask)(GL_TRUE); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glEnable)(GL_DEPTH_TEST); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glDepthFunc)(GL_ALWAYS); VOGL_CHECK_GL_ERROR; } GL_ENTRYPOINT(glDisable)(GL_STENCIL_TEST); VOGL_CHECK_GL_ERROR; uint32_t width = base_width << base_level; uint32_t height = base_height << base_level; uint32_t depth = base_depth; uint32_t max_possible_mip_levels = utils::compute_max_mips(width, height, depth); int num_actual_mip_levels = math::minimum<int>(max_possible_mip_levels, max_level + 1); for (int sample_index = 0; sample_index < samples; sample_index++) { m_read_color_program.set_uniform("tex_sample", sample_index); m_read_color_array_program.set_uniform("tex_sample", sample_index); m_read_depth_program.set_uniform("tex_sample", sample_index); m_read_depth_array_program.set_uniform("tex_sample", sample_index); GLuint dest_texture = 0; GL_ENTRYPOINT(glGenTextures)(1, &dest_texture); VOGL_CHECK_GL_ERROR; dest_textures.push_back(dest_texture); GL_ENTRYPOINT(glBindTexture)(dest_target, dest_texture); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glTexParameteri)(dest_target, GL_TEXTURE_BASE_LEVEL, base_level); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glTexParameteri)(dest_target, GL_TEXTURE_MAX_LEVEL, num_actual_mip_levels - 1); VOGL_CHECK_GL_ERROR; int mip_width = 0, mip_height = 0, mip_depth = 0; GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, mip_level, GL_TEXTURE_WIDTH, &mip_width); GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, mip_level, GL_TEXTURE_HEIGHT, &mip_height); GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, mip_level, GL_TEXTURE_DEPTH, &mip_depth); if ((vogl_check_gl_error()) || (mip_width < 1) || (mip_height < 1) || (mip_depth < 1)) goto failure; VOGL_ASSERT(mip_depth == base_depth); VOGL_NOTE_UNUSED(mip_depth); vogl::vector<uint8_t> ones; ones.resize(static_cast<uint32_t>(vogl_get_image_size(pInternal_tex_fmt->m_optimum_get_image_fmt, pInternal_tex_fmt->m_optimum_get_image_type, mip_width, mip_height, mip_depth))); ones.set_all(255); if (src_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) { GL_ENTRYPOINT(glTexImage3D)(dest_target, mip_level, internal_fmt, mip_width, mip_height, base_depth, 0, pInternal_tex_fmt->m_optimum_get_image_fmt, pInternal_tex_fmt->m_optimum_get_image_type, ones.get_ptr()); VOGL_CHECK_GL_ERROR; } else { GL_ENTRYPOINT(glTexImage2D)(dest_target, mip_level, internal_fmt, mip_width, mip_height, 0, pInternal_tex_fmt->m_optimum_get_image_fmt, pInternal_tex_fmt->m_optimum_get_image_type, ones.get_ptr()); VOGL_CHECK_GL_ERROR; } for (int layer = 0; layer < base_depth; layer++) { // 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; if (dest_target == GL_TEXTURE_2D_ARRAY) { GL_ENTRYPOINT(glFramebufferTextureLayer)(GL_DRAW_FRAMEBUFFER, attachment_target, dest_texture, mip_level, layer); VOGL_CHECK_GL_ERROR; } else { GL_ENTRYPOINT(glFramebufferTexture2D)(GL_DRAW_FRAMEBUFFER, attachment_target, dest_target, dest_texture, mip_level); VOGL_CHECK_GL_ERROR; } if (attachment_target == GL_COLOR_ATTACHMENT0) { GLenum draw_buf = GL_COLOR_ATTACHMENT0; GL_ENTRYPOINT(glDrawBuffers)(1, &draw_buf); VOGL_CHECK_GL_ERROR; } else { GL_ENTRYPOINT(glDrawBuffer)(GL_NONE); VOGL_CHECK_GL_ERROR; } GLenum fbo_status = GL_ENTRYPOINT(glCheckFramebufferStatus)(GL_DRAW_FRAMEBUFFER); VOGL_CHECK_GL_ERROR; bool status = false; if (fbo_status == GL_FRAMEBUFFER_COMPLETE) { // This method reads from a multisampled texture, which does NOT support GL_SKIP_DECODE_EXT on these targets. // Instead, we enable sRGB writes to work around this. The source and dest use the same formats, and if the dest is not sRGB then the source shouldn't be. GL_ENTRYPOINT(glDisable)(GL_FRAMEBUFFER_SRGB); VOGL_CHECK_GL_ERROR; if (attachment_target == GL_COLOR_ATTACHMENT0) { GLint encoding = 0; GL_ENTRYPOINT(glGetFramebufferAttachmentParameteriv)(GL_DRAW_FRAMEBUFFER, attachment_target, GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING, &encoding); VOGL_CHECK_GL_ERROR; if (encoding == GL_SRGB) { GL_ENTRYPOINT(glEnable)(GL_FRAMEBUFFER_SRGB); VOGL_CHECK_GL_ERROR; } } // Render quad to FBO GL_ENTRYPOINT(glViewport)(0, 0, mip_width, mip_height); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glClearColor)(1.0f, 0.3f, 1.0f, 1.0f); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glClearDepth)(.25f); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glClearStencil)(64); VOGL_CHECK_GL_ERROR; if (attachment_target == GL_COLOR_ATTACHMENT0) { GL_ENTRYPOINT(glClear)(GL_COLOR_BUFFER_BIT); VOGL_CHECK_GL_ERROR; } else if (attachment_target == GL_DEPTH_ATTACHMENT) { GL_ENTRYPOINT(glClear)(GL_DEPTH_BUFFER_BIT); VOGL_CHECK_GL_ERROR; } else { GL_ENTRYPOINT(glClear)(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); VOGL_CHECK_GL_ERROR; } vogl_quad_vertex quad_tri_verts[3*2]; memcpy(quad_tri_verts, get_quad_tri_verts(), sizeof(quad_tri_verts)); for (uint32_t i = 0; i < 6; i++) { quad_tri_verts[i].m_uv0[0] *= mip_width; quad_tri_verts[i].m_uv0[1] *= mip_height; quad_tri_verts[i].m_uv0[2] = 1.0f * layer; } GL_ENTRYPOINT(glBufferData)(GL_ARRAY_BUFFER, sizeof(quad_tri_verts), quad_tri_verts, GL_STATIC_DRAW); VOGL_CHECK_GL_ERROR; if (attachment_target == GL_COLOR_ATTACHMENT0) { GL_ENTRYPOINT(glUseProgram)((src_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) ? m_read_color_array_program.get_handle() : m_read_color_program.get_handle()); VOGL_CHECK_GL_ERROR; } else { GL_ENTRYPOINT(glUseProgram)((src_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) ? m_read_depth_array_program.get_handle() : m_read_depth_program.get_handle()); VOGL_CHECK_GL_ERROR; } GL_ENTRYPOINT(glDrawArrays)(GL_TRIANGLES, 0, 6); VOGL_CHECK_GL_ERROR; status = true; } // fbo_status // 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; if (!status) goto failure; } // layer } // sample_index GL_ENTRYPOINT(glBindTexture)(src_target, 0); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glBindTexture)(dest_target, 0); VOGL_CHECK_GL_ERROR; return true; failure: GL_ENTRYPOINT(glBindTexture)(src_target, 0); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glBindTexture)(dest_target, 0); VOGL_CHECK_GL_ERROR; if (dest_textures.size()) { GL_ENTRYPOINT(glDeleteTextures)(dest_textures.size(), dest_textures.get_ptr()); VOGL_CHECK_GL_ERROR; dest_textures.resize(0); } return false; }
// Copies MSAA color samples from an MSAA 2D to 2D_ARRAY texture to the stencil buffer of a MSAA 2D or 2D_ARRAY depth/stencil texture. // Source is NOT multisampled, dest is multisampled. bool vogl_msaa_texture_splitter::copy_color_sample_to_stencil( GLuint src_texture, uint32_t dest_sample_index, GLenum dest_target, GLuint dest_texture) { bool exit_status = false; if (!m_valid) { VOGL_ASSERT_ALWAYS; return false; } if ((dest_target != GL_TEXTURE_2D_MULTISAMPLE) && (dest_target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY)) { VOGL_ASSERT_ALWAYS; return false; } const GLenum src_target = (dest_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D; GL_ENTRYPOINT(glBindTexture)(src_target, src_texture); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glBindTexture)(dest_target, dest_texture); VOGL_CHECK_GL_ERROR; const int mip_level = 0; GLenum internal_fmt = 0; GL_ENTRYPOINT(glGetTexLevelParameteriv)(dest_target, mip_level, GL_TEXTURE_INTERNAL_FORMAT, reinterpret_cast<GLint *>(&internal_fmt)); int width = 0, height = 0, depth = 0, samples = 0; GL_ENTRYPOINT(glGetTexLevelParameteriv)(dest_target, mip_level, GL_TEXTURE_WIDTH, &width); GL_ENTRYPOINT(glGetTexLevelParameteriv)(dest_target, mip_level, GL_TEXTURE_HEIGHT, &height); GL_ENTRYPOINT(glGetTexLevelParameteriv)(dest_target, mip_level, GL_TEXTURE_DEPTH, &depth); GL_ENTRYPOINT(glGetTexLevelParameteriv)(dest_target, mip_level, GL_TEXTURE_SAMPLES, &samples); GL_ENTRYPOINT(glBindTexture)(dest_target, 0); VOGL_CHECK_GL_ERROR; if ((vogl_check_gl_error()) || (width < 1) || (height < 1) || (depth < 1) || (samples < 1)) return false; const vogl_internal_tex_format *pInternal_tex_fmt = vogl_find_internal_texture_format(internal_fmt); if ((!pInternal_tex_fmt) || (pInternal_tex_fmt->m_optimum_get_image_fmt == GL_NONE) || (pInternal_tex_fmt->m_optimum_get_image_type == GL_NONE)) return false; if (!pInternal_tex_fmt->m_comp_sizes[cTCStencil]) return false; GLenum fbo_attachment_target = GL_STENCIL_ATTACHMENT; if (pInternal_tex_fmt->m_comp_sizes[cTCDepth]) fbo_attachment_target = GL_DEPTH_STENCIL_ATTACHMENT; vogl_simple_gl_program &program = (dest_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) ? m_write_stencil_array_program : m_write_stencil_program; GL_ENTRYPOINT(glUseProgram)(program.get_handle()); VOGL_CHECK_GL_ERROR; program.set_uniform("sample_mask", static_cast<int>(1 << dest_sample_index)); GL_ENTRYPOINT(glColorMask)(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glStencilMask)(255); VOGL_CHECK_GL_ERROR; for (int layer = 0; layer < depth; layer++) { // 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; if (dest_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) { GL_ENTRYPOINT(glFramebufferTextureLayer)(GL_DRAW_FRAMEBUFFER, fbo_attachment_target, dest_texture, mip_level, layer); VOGL_CHECK_GL_ERROR; } else { GL_ENTRYPOINT(glFramebufferTexture2D)(GL_DRAW_FRAMEBUFFER, fbo_attachment_target, dest_target, dest_texture, mip_level); VOGL_CHECK_GL_ERROR; } GLenum draw_bufs[1] = { GL_NONE }; GL_ENTRYPOINT(glDrawBuffers)(1, draw_bufs); VOGL_CHECK_GL_ERROR; GLenum fbo_status = GL_ENTRYPOINT(glCheckFramebufferStatus)(GL_DRAW_FRAMEBUFFER); VOGL_CHECK_GL_ERROR; bool status = false; if (fbo_status == GL_FRAMEBUFFER_COMPLETE) { // Render quad to FBO GL_ENTRYPOINT(glViewport)(0, 0, width, height); VOGL_CHECK_GL_ERROR; if (!dest_sample_index) { GL_ENTRYPOINT(glClearStencil)(0); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glClear)(GL_STENCIL_BUFFER_BIT); VOGL_CHECK_GL_ERROR; } vogl_quad_vertex quad_tri_verts[3*2]; memcpy(quad_tri_verts, get_quad_tri_verts(), sizeof(quad_tri_verts)); for (uint32_t i = 0; i < 6; i++) { quad_tri_verts[i].m_uv0[0] *= width; quad_tri_verts[i].m_uv0[1] *= height; quad_tri_verts[i].m_uv0[2] = 1.0f * layer; } GL_ENTRYPOINT(glBufferData)(GL_ARRAY_BUFFER, sizeof(quad_tri_verts), quad_tri_verts, GL_STATIC_DRAW); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glEnable)(GL_DEPTH_TEST); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glDepthMask)(GL_FALSE); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glDepthFunc)(GL_ALWAYS); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glEnable)(GL_STENCIL_TEST); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glStencilOp)(GL_KEEP, GL_KEEP, GL_REPLACE); VOGL_CHECK_GL_ERROR; for (uint32_t stencil_val = 0; stencil_val <= 255; stencil_val++) { program.set_uniform("stencil_comp_val", stencil_val / 255.0f); GL_ENTRYPOINT(glStencilFunc)(GL_ALWAYS, stencil_val, 0xFF); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glDrawArrays)(GL_TRIANGLES, 0, 6); VOGL_CHECK_GL_ERROR; } // stencil_val status = true; } // fbo_status // 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; if (!status) goto failure; } // layer exit_status = true; failure: GL_ENTRYPOINT(glBindTexture)(src_target, 0); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glBindTexture)(dest_target, 0); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glColorMask)(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glDisable)(GL_STENCIL_TEST); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glStencilMask)(0); VOGL_CHECK_GL_ERROR; return exit_status; }
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; }
bool vogl_query_state::restore(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 &handle) const { VOGL_FUNC_TRACER VOGL_NOTE_UNUSED(context_info); if (!m_is_valid) return false; bool created_handle = false; if (!handle) { GLuint handle32 = 0; GL_ENTRYPOINT(glGenQueries)(1, &handle32); if ((vogl_check_gl_error()) || (!handle32)) return false; handle = handle32; remapper.declare_handle(VOGL_NAMESPACE_QUERIES, m_snapshot_handle, handle, m_target); VOGL_ASSERT(remapper.remap_handle(VOGL_NAMESPACE_QUERIES, m_snapshot_handle) == handle); created_handle = true; } // m_target will be GL_NONE if the query has been genned but not begun up to this point. if ((m_target != GL_NONE) && (m_has_been_begun)) { GLuint prev_query = 0; GL_ENTRYPOINT(glGetQueryiv)(m_target, GL_CURRENT_QUERY, reinterpret_cast<GLint *>(&prev_query)); VOGL_CHECK_GL_ERROR; VOGL_ASSERT(handle <= cUINT32_MAX); // Begin end the restore query, so it becomes a valid name. GL_ENTRYPOINT(glBeginQuery)(m_target, static_cast<GLuint>(handle)); if (vogl_check_gl_error()) goto handle_error; GL_ENTRYPOINT(glEndQuery)(m_target); if (vogl_check_gl_error()) goto handle_error; if (prev_query) { // Now begin/end the original query so it's active again. The query API sucks. GL_ENTRYPOINT(glBeginQuery)(m_target, prev_query); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glEndQuery)(m_target); VOGL_CHECK_GL_ERROR; } } return true; handle_error: if ((handle) && (created_handle)) { remapper.delete_handle_and_object(VOGL_NAMESPACE_QUERIES, m_snapshot_handle, handle); //GLuint handle32 = static_cast<GLuint>(handle); //GL_ENTRYPOINT(glDeleteQueries)(1, &handle32); //VOGL_CHECK_GL_ERROR; handle = 0; } return false; }
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; }
// Multiple sources, one multisampled destination. Caller creates destination. bool vogl_msaa_texture_splitter::combine(GLuint src_texture, uint32_t dest_sample_index, GLenum dest_target, GLuint dest_texture) { if (!m_valid) { VOGL_ASSERT_ALWAYS; return false; } if ((dest_target != GL_TEXTURE_2D_MULTISAMPLE) && (dest_target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY)) { VOGL_ASSERT_ALWAYS; return false; } m_write_color_program.set_uniform("sample_mask", static_cast<int>(1U << dest_sample_index)); m_write_color_array_program.set_uniform("sample_mask", static_cast<int>(1U << dest_sample_index)); m_write_depth_program.set_uniform("sample_mask", static_cast<int>(1U << dest_sample_index)); m_write_depth_array_program.set_uniform("sample_mask", static_cast<int>(1U << dest_sample_index)); const GLenum src_target = (dest_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D; GL_ENTRYPOINT(glBindTexture)(src_target, src_texture); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glBindTexture)(dest_target, dest_texture); VOGL_CHECK_GL_ERROR; const int mip_level = 0; GLenum internal_fmt = 0; GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, mip_level, GL_TEXTURE_INTERNAL_FORMAT, reinterpret_cast<GLint *>(&internal_fmt)); int mip_width = 0, mip_height = 0, mip_depth = 0; GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, mip_level, GL_TEXTURE_WIDTH, &mip_width); GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, mip_level, GL_TEXTURE_HEIGHT, &mip_height); GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, mip_level, GL_TEXTURE_DEPTH, &mip_depth); if ((vogl_check_gl_error()) || (mip_width < 1) || (mip_height < 1) || (mip_depth < 1)) return false; const vogl_internal_tex_format *pInternal_tex_fmt = vogl_find_internal_texture_format(internal_fmt); if ((!pInternal_tex_fmt) || (pInternal_tex_fmt->m_optimum_get_image_fmt == GL_NONE) || (pInternal_tex_fmt->m_optimum_get_image_type == GL_NONE)) return false; GLenum attachment_target = GL_COLOR_ATTACHMENT0; if ((pInternal_tex_fmt->m_comp_sizes[cTCDepth]) && (pInternal_tex_fmt->m_comp_sizes[cTCStencil])) attachment_target = GL_DEPTH_STENCIL_ATTACHMENT; else if (pInternal_tex_fmt->m_comp_sizes[cTCDepth]) attachment_target = GL_DEPTH_ATTACHMENT; else if (pInternal_tex_fmt->m_comp_sizes[cTCStencil]) return false; if (attachment_target == GL_COLOR_ATTACHMENT0) { GL_ENTRYPOINT(glDepthMask)(GL_FALSE); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glDisable)(GL_DEPTH_TEST); VOGL_CHECK_GL_ERROR; } else { GL_ENTRYPOINT(glDepthMask)(GL_TRUE); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glEnable)(GL_DEPTH_TEST); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glDepthFunc)(GL_ALWAYS); VOGL_CHECK_GL_ERROR; } GL_ENTRYPOINT(glDisable)(GL_STENCIL_TEST); VOGL_CHECK_GL_ERROR; // This method disables sRGB reads and writes (we can do this because the source is non-multisampled and the dest is a multisampled render target.) GLint orig_srgb_decode = 0; if (m_context_info.supports_extension("GL_EXT_texture_sRGB_decode")) { GL_ENTRYPOINT(glGetTexParameteriv)(src_target, GL_TEXTURE_SRGB_DECODE_EXT, &orig_srgb_decode); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glTexParameteri)(src_target, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT); VOGL_CHECK_GL_ERROR; } for (int layer = 0; layer < mip_depth; layer++) { // 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; if (dest_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) { GL_ENTRYPOINT(glFramebufferTextureLayer)(GL_DRAW_FRAMEBUFFER, attachment_target, dest_texture, mip_level, layer); VOGL_CHECK_GL_ERROR; } else { GL_ENTRYPOINT(glFramebufferTexture2D)(GL_DRAW_FRAMEBUFFER, attachment_target, dest_target, dest_texture, mip_level); VOGL_CHECK_GL_ERROR; } if (attachment_target == GL_COLOR_ATTACHMENT0) { GLenum draw_buf = GL_COLOR_ATTACHMENT0; GL_ENTRYPOINT(glDrawBuffers)(1, &draw_buf); VOGL_CHECK_GL_ERROR; } else { GL_ENTRYPOINT(glDrawBuffer)(GL_NONE); VOGL_CHECK_GL_ERROR; } GLenum fbo_status = GL_ENTRYPOINT(glCheckFramebufferStatus)(GL_DRAW_FRAMEBUFFER); VOGL_CHECK_GL_ERROR; bool status = false; if (fbo_status == GL_FRAMEBUFFER_COMPLETE) { // Render quad to FBO GL_ENTRYPOINT(glViewport)(0, 0, mip_width, mip_height); VOGL_CHECK_GL_ERROR; vogl_quad_vertex quad_tri_verts[3*2]; memcpy(quad_tri_verts, get_quad_tri_verts(), sizeof(quad_tri_verts)); for (uint32_t i = 0; i < 6; i++) { quad_tri_verts[i].m_uv0[0] *= mip_width; quad_tri_verts[i].m_uv0[1] *= mip_height; quad_tri_verts[i].m_uv0[2] = 1.0f * layer; } GL_ENTRYPOINT(glBufferData)(GL_ARRAY_BUFFER, sizeof(quad_tri_verts), quad_tri_verts, GL_STATIC_DRAW); VOGL_CHECK_GL_ERROR; if (attachment_target == GL_COLOR_ATTACHMENT0) { GL_ENTRYPOINT(glUseProgram)((src_target == GL_TEXTURE_2D_ARRAY) ? m_write_color_array_program.get_handle() : m_write_color_program.get_handle()); VOGL_CHECK_GL_ERROR; } else { GL_ENTRYPOINT(glUseProgram)((src_target == GL_TEXTURE_2D_ARRAY) ? m_write_depth_array_program.get_handle() : m_write_depth_program.get_handle()); VOGL_CHECK_GL_ERROR; } GL_ENTRYPOINT(glDisable)(GL_FRAMEBUFFER_SRGB); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glDrawArrays)(GL_TRIANGLES, 0, 6); VOGL_CHECK_GL_ERROR; status = true; } // fbo_status // 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; if (!status) goto failure; } // layer GL_ENTRYPOINT(glBindTexture)(src_target, 0); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glBindTexture)(dest_target, 0); VOGL_CHECK_GL_ERROR; return true; failure: GL_ENTRYPOINT(glBindTexture)(src_target, 0); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glBindTexture)(dest_target, 0); VOGL_CHECK_GL_ERROR; if (m_context_info.supports_extension("GL_EXT_texture_sRGB_decode")) { GL_ENTRYPOINT(glTexParameteri)(src_target, GL_TEXTURE_SRGB_DECODE_EXT, orig_srgb_decode); VOGL_CHECK_GL_ERROR; } return false; }
bool vogl_renderbuffer_state::restore(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 &handle) const { VOGL_FUNC_TRACER VOGL_ASSERT(context_info.get_version() >= VOGL_GL_VERSION_3_0); if (!m_is_valid) return false; vogl_scoped_binding_state orig_renderbuffer(GL_RENDERBUFFER); bool created_handle = false; if (!handle) { GLuint handle32 = 0; GL_ENTRYPOINT(glGenRenderbuffers)(1, &handle32); if ((vogl_check_gl_error()) || (!handle32)) return false; handle = handle32; remapper.declare_handle(VOGL_NAMESPACE_RENDER_BUFFERS, m_snapshot_handle, handle, GL_NONE); VOGL_ASSERT(remapper.remap_handle(VOGL_NAMESPACE_RENDER_BUFFERS, m_snapshot_handle) == handle); created_handle = true; } GL_ENTRYPOINT(glBindRenderbuffer)(GL_RENDERBUFFER, static_cast<GLuint>(handle)); if (vogl_check_gl_error()) goto handle_error; if ((m_desc.m_width) && (m_desc.m_height) && (m_desc.m_internal_format)) { if (!m_desc.restore(context_info)) goto handle_error; if (m_texture.is_valid()) { GLenum attachment = GL_COLOR_ATTACHMENT0; GLenum draw_and_read_buf = GL_COLOR_ATTACHMENT0; GLenum blit_type = GL_COLOR_BUFFER_BIT; if ((m_desc.m_depth_size) && (m_desc.m_stencil_size)) { attachment = GL_DEPTH_STENCIL_ATTACHMENT; draw_and_read_buf = GL_NONE; blit_type = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; } else if (m_desc.m_depth_size) { attachment = GL_DEPTH_ATTACHMENT; draw_and_read_buf = GL_NONE; blit_type = GL_DEPTH_BUFFER_BIT; } else if (m_desc.m_stencil_size) { attachment = GL_STENCIL_ATTACHMENT; draw_and_read_buf = GL_NONE; blit_type = GL_STENCIL_BUFFER_BIT; } bool restore_status = false; GLuint64 tex_handle64 = 0; vogl_handle_remapper def_handle_remapper; if (m_texture.restore(context_info, def_handle_remapper, tex_handle64)) { GLuint tex_handle = static_cast<GLuint>(tex_handle64); const GLenum tex_target = (m_desc.m_samples > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D; GLuint src_fbo_handle = 0, dst_fbo_handle = 0; // Source FBO GL_ENTRYPOINT(glGenFramebuffers)(1, &src_fbo_handle); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glBindFramebuffer)(GL_READ_FRAMEBUFFER, src_fbo_handle); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glFramebufferTexture2D)(GL_READ_FRAMEBUFFER, attachment, tex_target, tex_handle, 0); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glReadBuffer)(draw_and_read_buf); VOGL_CHECK_GL_ERROR; // Dest FBO GL_ENTRYPOINT(glGenFramebuffers)(1, &dst_fbo_handle); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, dst_fbo_handle); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glFramebufferRenderbuffer)(GL_DRAW_FRAMEBUFFER, attachment, GL_RENDERBUFFER, static_cast<GLuint>(handle)); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glDrawBuffers)(1, &draw_and_read_buf); VOGL_CHECK_GL_ERROR; GLenum read_status = GL_ENTRYPOINT(glCheckFramebufferStatus)(GL_READ_FRAMEBUFFER); VOGL_CHECK_GL_ERROR; GLenum draw_status = GL_ENTRYPOINT(glCheckFramebufferStatus)(GL_DRAW_FRAMEBUFFER); VOGL_CHECK_GL_ERROR; if ((read_status = GL_FRAMEBUFFER_COMPLETE) && (draw_status == GL_FRAMEBUFFER_COMPLETE)) { #if 0 // HACK HACK HACK if (m_texture.get_num_samples() > 1) { uint base_level = m_texture.get_params().get_value<GLenum>(GL_TEXTURE_BASE_LEVEL); if (base_level < m_texture.get_num_levels()) { const vogl_state_vector &state_vec = m_texture.get_level_params(0, base_level); uint clear_mask = 0; if (state_vec.get_value<GLenum>(GL_TEXTURE_DEPTH_SIZE)) { clear_mask |= GL_DEPTH_BUFFER_BIT; } if (state_vec.get_value<GLenum>(GL_TEXTURE_STENCIL_SIZE)) { clear_mask |= GL_STENCIL_BUFFER_BIT; } if (state_vec.get_value<GLenum>(GL_TEXTURE_RED_SIZE) + state_vec.get_value<GLenum>(GL_TEXTURE_GREEN_SIZE) + state_vec.get_value<GLenum>(GL_TEXTURE_BLUE_SIZE) + state_vec.get_value<GLenum>(GL_TEXTURE_ALPHA_SIZE) + state_vec.get_value<GLenum>(GL_TEXTURE_INTENSITY_SIZE) + state_vec.get_value<GLenum>(GL_TEXTURE_LUMINANCE_SIZE)) { clear_mask |= GL_COLOR_BUFFER_BIT; } GL_ENTRYPOINT(glClearColor)(1.0f, 0.0f, 1.0f, 1.0f); GL_ENTRYPOINT(glClearDepth)(.5f); GL_ENTRYPOINT(glClearStencil)(128); GL_ENTRYPOINT(glClear)(clear_mask); VOGL_CHECK_GL_ERROR; } } else #endif { GL_ENTRYPOINT(glBlitFramebuffer)( 0, 0, m_desc.m_width, m_desc.m_height, 0, 0, m_desc.m_width, m_desc.m_height, blit_type, GL_NEAREST); if (!vogl_check_gl_error_internal()) { restore_status = true; } } } // Delete FBO GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, 0); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glDeleteFramebuffers)(1, &dst_fbo_handle); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glBindFramebuffer)(GL_READ_FRAMEBUFFER, 0); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glDeleteFramebuffers)(1, &src_fbo_handle); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glDeleteTextures)(1, &tex_handle); VOGL_CHECK_GL_ERROR; } if (!restore_status) { vogl_error_printf("%s: Failed restoring contents of renderbuffer %u\n", VOGL_METHOD_NAME, static_cast<GLuint>(handle)); } } } return true; handle_error: if (created_handle) { GL_ENTRYPOINT(glBindRenderbuffer)(GL_RENDERBUFFER, 0); VOGL_CHECK_GL_ERROR; remapper.delete_handle_and_object(VOGL_NAMESPACE_RENDER_BUFFERS, m_snapshot_handle, handle); //GLuint handle32 = static_cast<GLuint>(handle); //GL_ENTRYPOINT(glDeleteRenderbuffers)(1, &handle32); //VOGL_CHECK_GL_ERROR; handle = 0; } return false; }
bool vogl_msaa_texture_splitter::copy_stencil_samples_to_color(GLenum target, GLuint src_texture, GLuint &dest_texture) { dest_texture = 0; if (!m_valid) { VOGL_ASSERT_ALWAYS; return false; } if ((target != GL_TEXTURE_2D_MULTISAMPLE) && (target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY)) { VOGL_ASSERT_ALWAYS; return false; } GL_ENTRYPOINT(glBindTexture)(target, src_texture); VOGL_CHECK_GL_ERROR; const int mip_level = 0; GLenum internal_fmt = 0; GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, mip_level, GL_TEXTURE_INTERNAL_FORMAT, reinterpret_cast<GLint *>(&internal_fmt)); int width = 0, height = 0, depth = 0, samples = 0; GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, mip_level, GL_TEXTURE_WIDTH, &width); GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, mip_level, GL_TEXTURE_HEIGHT, &height); GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, mip_level, GL_TEXTURE_DEPTH, &depth); GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, mip_level, GL_TEXTURE_SAMPLES, &samples); if ((vogl_check_gl_error()) || (width < 1) || (height < 1) || (depth < 1) || (samples < 1)) return false; const vogl_internal_tex_format *pInternal_tex_fmt = vogl_find_internal_texture_format(internal_fmt); if ((!pInternal_tex_fmt) || (pInternal_tex_fmt->m_optimum_get_image_fmt == GL_NONE) || (pInternal_tex_fmt->m_optimum_get_image_type == GL_NONE)) return false; if (!pInternal_tex_fmt->m_comp_sizes[cTCStencil]) return false; GLenum fbo_attachment_target = GL_STENCIL_ATTACHMENT; if (pInternal_tex_fmt->m_comp_sizes[cTCDepth]) fbo_attachment_target = GL_DEPTH_STENCIL_ATTACHMENT; GL_ENTRYPOINT(glGenTextures)(1, &dest_texture); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glBindTexture)(target, dest_texture); VOGL_CHECK_GL_ERROR; const GLenum dest_internal_fmt = GL_RGBA; const GLboolean fixed_sample_locations = GL_TRUE; if (target == GL_TEXTURE_2D_MULTISAMPLE) { GL_ENTRYPOINT(glTexImage2DMultisample)(target, samples, dest_internal_fmt, width, height, fixed_sample_locations); VOGL_CHECK_GL_ERROR; } else { GL_ENTRYPOINT(glTexImage3DMultisample)(target, samples, dest_internal_fmt, width, height, depth, fixed_sample_locations); VOGL_CHECK_GL_ERROR; } GL_ENTRYPOINT(glUseProgram)(m_const_color_program.get_handle()); VOGL_CHECK_GL_ERROR; for (int layer = 0; layer < depth; layer++) { GLuint temp_fbo = 0; GL_ENTRYPOINT(glGenFramebuffers)(1, &temp_fbo); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, temp_fbo); VOGL_CHECK_GL_ERROR; if (target == GL_TEXTURE_2D_MULTISAMPLE) { GL_ENTRYPOINT(glFramebufferTexture2D)(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, dest_texture, mip_level); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glFramebufferTexture2D)(GL_DRAW_FRAMEBUFFER, fbo_attachment_target, target, src_texture, mip_level); VOGL_CHECK_GL_ERROR; } else { GL_ENTRYPOINT(glFramebufferTextureLayer)(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dest_texture, mip_level, layer); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glFramebufferTextureLayer)(GL_DRAW_FRAMEBUFFER, fbo_attachment_target, src_texture, mip_level, layer); VOGL_CHECK_GL_ERROR; } GLenum draw_buf = GL_COLOR_ATTACHMENT0; GL_ENTRYPOINT(glDrawBuffers)(1, &draw_buf); VOGL_CHECK_GL_ERROR; GLenum fbo_status = GL_ENTRYPOINT(glCheckFramebufferStatus)(GL_DRAW_FRAMEBUFFER); VOGL_CHECK_GL_ERROR; bool status = false; if (fbo_status == GL_FRAMEBUFFER_COMPLETE) { GL_ENTRYPOINT(glDisable)(GL_FRAMEBUFFER_SRGB); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glViewport)(0, 0, width, height); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glClearColor)(0, 0, 0, 0); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glClear)(GL_COLOR_BUFFER_BIT); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glColorMask)(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glEnable)(GL_DEPTH_TEST); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glDepthMask)(GL_FALSE); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glDepthFunc)(GL_ALWAYS); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glEnable)(GL_STENCIL_TEST); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glStencilOp)(GL_KEEP, GL_KEEP, GL_REPLACE); VOGL_CHECK_GL_ERROR; vogl_quad_vertex quad_tri_verts[3*2]; memcpy(quad_tri_verts, get_quad_tri_verts(), sizeof(quad_tri_verts)); for (uint32_t i = 0; i < 6; i++) { quad_tri_verts[i].m_uv0[0] *= width; quad_tri_verts[i].m_uv0[1] *= height; quad_tri_verts[i].m_uv0[2] = 1.0f * layer; } GL_ENTRYPOINT(glBufferData)(GL_ARRAY_BUFFER, sizeof(quad_tri_verts), quad_tri_verts, GL_STATIC_DRAW); VOGL_CHECK_GL_ERROR; for (uint32_t stencil_val = 0; stencil_val <= 255; stencil_val++) { m_const_color_program.set_uniform("color", vec4F(stencil_val * (1.0f / 255.0f))); GL_ENTRYPOINT(glStencilFunc)(GL_EQUAL, stencil_val, 0xFF); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glDrawArrays)(GL_TRIANGLES, 0, 6); VOGL_CHECK_GL_ERROR; } // stencil_val status = true; } // fbo_status GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, 0); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glDeleteFramebuffers)(1, &temp_fbo); VOGL_CHECK_GL_ERROR; temp_fbo = 0; if (!status) goto failure; } // layer GL_ENTRYPOINT(glBindTexture)(target, 0); VOGL_CHECK_GL_ERROR; GL_ENTRYPOINT(glDisable)(GL_STENCIL_TEST); VOGL_CHECK_GL_ERROR; return true; failure: GL_ENTRYPOINT(glBindTexture)(target, 0); VOGL_CHECK_GL_ERROR; if (dest_texture) { GL_ENTRYPOINT(glDeleteTextures)(1, &dest_texture); VOGL_CHECK_GL_ERROR; dest_texture = 0; } GL_ENTRYPOINT(glDisable)(GL_STENCIL_TEST); VOGL_CHECK_GL_ERROR; return false; }
//---------------------------------------------------------------------------------------------------------------------- // 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); }