From e3f4233cefff611e03a2031c6194a118d946a5d9 Mon Sep 17 00:00:00 2001 From: Subv Date: Sat, 25 Jul 2015 20:13:11 -0500 Subject: Initial implementation of fragment shader generation with caching. --- src/video_core/renderer_opengl/gl_rasterizer.cpp | 351 ++++++++--------------- 1 file changed, 124 insertions(+), 227 deletions(-) (limited to 'src/video_core/renderer_opengl/gl_rasterizer.cpp') diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index a613fe136..45329d561 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -8,6 +8,7 @@ #include #include "common/color.h" +#include "common/file_util.h" #include "common/math_util.h" #include "common/microprofile.h" #include "common/profiler.h" @@ -38,36 +39,6 @@ RasterizerOpenGL::RasterizerOpenGL() : last_fb_color_addr(0), last_fb_depth_addr RasterizerOpenGL::~RasterizerOpenGL() { } void RasterizerOpenGL::InitObjects() { - // Create the hardware shader program and get attrib/uniform locations - shader.Create(GLShaders::g_vertex_shader_hw, GLShaders::g_fragment_shader_hw); - attrib_position = glGetAttribLocation(shader.handle, "vert_position"); - attrib_color = glGetAttribLocation(shader.handle, "vert_color"); - attrib_texcoords = glGetAttribLocation(shader.handle, "vert_texcoords"); - - uniform_alphatest_enabled = glGetUniformLocation(shader.handle, "alphatest_enabled"); - uniform_alphatest_func = glGetUniformLocation(shader.handle, "alphatest_func"); - uniform_alphatest_ref = glGetUniformLocation(shader.handle, "alphatest_ref"); - - uniform_tex = glGetUniformLocation(shader.handle, "tex"); - - uniform_tev_combiner_buffer_color = glGetUniformLocation(shader.handle, "tev_combiner_buffer_color"); - - const auto tev_stages = Pica::g_state.regs.GetTevStages(); - for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); ++tev_stage_index) { - auto& uniform_tev_cfg = uniform_tev_cfgs[tev_stage_index]; - - std::string tev_ref_str = "tev_cfgs[" + std::to_string(tev_stage_index) + "]"; - uniform_tev_cfg.enabled = glGetUniformLocation(shader.handle, (tev_ref_str + ".enabled").c_str()); - uniform_tev_cfg.color_sources = glGetUniformLocation(shader.handle, (tev_ref_str + ".color_sources").c_str()); - uniform_tev_cfg.alpha_sources = glGetUniformLocation(shader.handle, (tev_ref_str + ".alpha_sources").c_str()); - uniform_tev_cfg.color_modifiers = glGetUniformLocation(shader.handle, (tev_ref_str + ".color_modifiers").c_str()); - uniform_tev_cfg.alpha_modifiers = glGetUniformLocation(shader.handle, (tev_ref_str + ".alpha_modifiers").c_str()); - uniform_tev_cfg.color_alpha_op = glGetUniformLocation(shader.handle, (tev_ref_str + ".color_alpha_op").c_str()); - uniform_tev_cfg.color_alpha_multiplier = glGetUniformLocation(shader.handle, (tev_ref_str + ".color_alpha_multiplier").c_str()); - uniform_tev_cfg.const_color = glGetUniformLocation(shader.handle, (tev_ref_str + ".const_color").c_str()); - uniform_tev_cfg.updates_combiner_buffer_color_alpha = glGetUniformLocation(shader.handle, (tev_ref_str + ".updates_combiner_buffer_color_alpha").c_str()); - } - // Create sampler objects for (size_t i = 0; i < texture_samplers.size(); ++i) { texture_samplers[i].Create(); @@ -78,29 +49,25 @@ void RasterizerOpenGL::InitObjects() { vertex_buffer.Create(); vertex_array.Create(); - // Update OpenGL state state.draw.vertex_array = vertex_array.handle; state.draw.vertex_buffer = vertex_buffer.handle; - state.draw.shader_program = shader.handle; - state.Apply(); - // Set the texture samplers to correspond to different texture units - glUniform1i(uniform_tex, 0); - glUniform1i(uniform_tex + 1, 1); - glUniform1i(uniform_tex + 2, 2); - // Set vertex attributes - glVertexAttribPointer(attrib_position, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, position)); - glVertexAttribPointer(attrib_color, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, color)); - glVertexAttribPointer(attrib_texcoords, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0)); - glVertexAttribPointer(attrib_texcoords + 1, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord1)); - glVertexAttribPointer(attrib_texcoords + 2, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord2)); - glEnableVertexAttribArray(attrib_position); - glEnableVertexAttribArray(attrib_color); - glEnableVertexAttribArray(attrib_texcoords); - glEnableVertexAttribArray(attrib_texcoords + 1); - glEnableVertexAttribArray(attrib_texcoords + 2); + glVertexAttribPointer(ShaderUtil::ATTRIBUTE_POSITION, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, position)); + glEnableVertexAttribArray(ShaderUtil::ATTRIBUTE_POSITION); + + glVertexAttribPointer(ShaderUtil::ATTRIBUTE_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, color)); + glEnableVertexAttribArray(ShaderUtil::ATTRIBUTE_COLOR); + + glVertexAttribPointer(ShaderUtil::ATTRIBUTE_TEXCOORDS, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0)); + glVertexAttribPointer(ShaderUtil::ATTRIBUTE_TEXCOORDS + 1, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord1)); + glVertexAttribPointer(ShaderUtil::ATTRIBUTE_TEXCOORDS + 2, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord2)); + glEnableVertexAttribArray(ShaderUtil::ATTRIBUTE_TEXCOORDS); + glEnableVertexAttribArray(ShaderUtil::ATTRIBUTE_TEXCOORDS + 1); + glEnableVertexAttribArray(ShaderUtil::ATTRIBUTE_TEXCOORDS + 2); + + RegenerateShaders(); // Create textures for OGL framebuffer that will be rendered to, initially 1x1 to succeed in framebuffer creation fb_color_texture.texture.Create(); @@ -156,55 +123,11 @@ void RasterizerOpenGL::Reset() { SyncBlendEnabled(); SyncBlendFuncs(); SyncBlendColor(); - SyncAlphaTest(); SyncLogicOp(); SyncStencilTest(); SyncDepthTest(); - // TEV stage 0 - SyncTevSources(0, regs.tev_stage0); - SyncTevModifiers(0, regs.tev_stage0); - SyncTevOps(0, regs.tev_stage0); - SyncTevColor(0, regs.tev_stage0); - SyncTevMultipliers(0, regs.tev_stage0); - - // TEV stage 1 - SyncTevSources(1, regs.tev_stage1); - SyncTevModifiers(1, regs.tev_stage1); - SyncTevOps(1, regs.tev_stage1); - SyncTevColor(1, regs.tev_stage1); - SyncTevMultipliers(1, regs.tev_stage1); - - // TEV stage 2 - SyncTevSources(2, regs.tev_stage2); - SyncTevModifiers(2, regs.tev_stage2); - SyncTevOps(2, regs.tev_stage2); - SyncTevColor(2, regs.tev_stage2); - SyncTevMultipliers(2, regs.tev_stage2); - - // TEV stage 3 - SyncTevSources(3, regs.tev_stage3); - SyncTevModifiers(3, regs.tev_stage3); - SyncTevOps(3, regs.tev_stage3); - SyncTevColor(3, regs.tev_stage3); - SyncTevMultipliers(3, regs.tev_stage3); - - // TEV stage 4 - SyncTevSources(4, regs.tev_stage4); - SyncTevModifiers(4, regs.tev_stage4); - SyncTevOps(4, regs.tev_stage4); - SyncTevColor(4, regs.tev_stage4); - SyncTevMultipliers(4, regs.tev_stage4); - - // TEV stage 5 - SyncTevSources(5, regs.tev_stage5); - SyncTevModifiers(5, regs.tev_stage5); - SyncTevOps(5, regs.tev_stage5); - SyncTevColor(5, regs.tev_stage5); - SyncTevMultipliers(5, regs.tev_stage5); - - SyncCombinerColor(); - SyncCombinerWriteFlags(); + RegenerateShaders(); res_cache.FullFlush(); } @@ -217,10 +140,88 @@ void RasterizerOpenGL::AddTriangle(const Pica::Shader::OutputVertex& v0, vertex_batch.emplace_back(v2); } +namespace ShaderCache { +extern std::string GenerateFragmentShader(const ShaderCacheKey& config); +} + +void RasterizerOpenGL::RegenerateShaders() { + const auto& regs = Pica::g_state.regs; + + ShaderCacheKey config; + config.alpha_test_func = regs.output_merger.alpha_test.enable ? + regs.output_merger.alpha_test.func.Value() : Pica::Regs::CompareFunc::Always; + config.tev_stages = regs.GetTevStages(); + for (auto& tev : config.tev_stages) { + tev.const_r = 0; + tev.const_g = 0; + tev.const_b = 0; + tev.const_a = 0; + } + config.combiner_buffer_input = + regs.tev_combiner_buffer_input.update_mask_rgb.Value() | + regs.tev_combiner_buffer_input.update_mask_a.Value() << 4; + + auto cached_shader = shader_cache.find(config); + if (cached_shader != shader_cache.end()) { + current_shader = &cached_shader->second; + state.draw.shader_program = current_shader->shader.handle; + state.Apply(); + } else { + LOG_CRITICAL(Render_OpenGL, "Creating new shader: %08X", hash(config)); + + TEVShader shader; + + std::string fragShader = ShaderCache::GenerateFragmentShader(config); + shader.shader.Create(GLShaders::g_vertex_shader_hw, fragShader.c_str()); + + shader.uniform_alphatest_ref = glGetUniformLocation(shader.shader.handle, "alphatest_ref"); + shader.uniform_tex = glGetUniformLocation(shader.shader.handle, "tex"); + shader.uniform_tev_combiner_buffer_color = glGetUniformLocation(shader.shader.handle, "tev_combiner_buffer_color"); + shader.uniform_tev_const_colors = glGetUniformLocation(shader.shader.handle, "const_color"); + + current_shader = &shader_cache.emplace(config, std::move(shader)).first->second; + + state.draw.shader_program = current_shader->shader.handle; + state.Apply(); + + // Set the texture samplers to correspond to different texture units + if (shader.uniform_tex != -1) { + glUniform1i(shader.uniform_tex, 0); + glUniform1i(shader.uniform_tex + 1, 1); + glUniform1i(shader.uniform_tex + 2, 2); + } + } + + + // Sync alpha reference + if (current_shader->uniform_alphatest_ref != -1) + glUniform1f(current_shader->uniform_alphatest_ref, regs.output_merger.alpha_test.ref / 255.0f); + + // Sync combiner buffer color + if (current_shader->uniform_tev_combiner_buffer_color != -1) { + auto combiner_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.tev_combiner_buffer_color.raw); + glUniform4fv(current_shader->uniform_tev_combiner_buffer_color, 1, combiner_color.data()); + } + + // Sync TEV const colors + if (current_shader->uniform_tev_const_colors != -1) { + auto& tev_stages = Pica::g_state.regs.GetTevStages(); + for (int tev_index = 0; tev_index < tev_stages.size(); ++tev_index) { + auto const_color = PicaToGL::ColorRGBA8(tev_stages[tev_index].const_color); + glUniform4fv(current_shader->uniform_tev_const_colors + tev_index, 1, const_color.data()); + } + } +} + void RasterizerOpenGL::DrawTriangles() { SyncFramebuffer(); SyncDrawState(); + if (state.draw.shader_dirty) { + RegenerateShaders(); + state.draw.shader_dirty = false; + } + glBufferData(GL_ARRAY_BUFFER, vertex_batch.size() * sizeof(HardwareVertex), vertex_batch.data(), GL_STREAM_DRAW); glDrawArrays(GL_TRIANGLES, 0, (GLsizei)vertex_batch.size()); @@ -272,6 +273,7 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { // Alpha test case PICA_REG_INDEX(output_merger.alpha_test): SyncAlphaTest(); + state.draw.shader_dirty = true; break; // Stencil test @@ -290,117 +292,57 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { SyncLogicOp(); break; - // TEV stage 0 + // TEV stages case PICA_REG_INDEX(tev_stage0.color_source1): - SyncTevSources(0, regs.tev_stage0); - break; case PICA_REG_INDEX(tev_stage0.color_modifier1): - SyncTevModifiers(0, regs.tev_stage0); - break; case PICA_REG_INDEX(tev_stage0.color_op): - SyncTevOps(0, regs.tev_stage0); - break; - case PICA_REG_INDEX(tev_stage0.const_r): - SyncTevColor(0, regs.tev_stage0); - break; case PICA_REG_INDEX(tev_stage0.color_scale): - SyncTevMultipliers(0, regs.tev_stage0); - break; - - // TEV stage 1 case PICA_REG_INDEX(tev_stage1.color_source1): - SyncTevSources(1, regs.tev_stage1); - break; case PICA_REG_INDEX(tev_stage1.color_modifier1): - SyncTevModifiers(1, regs.tev_stage1); - break; case PICA_REG_INDEX(tev_stage1.color_op): - SyncTevOps(1, regs.tev_stage1); - break; - case PICA_REG_INDEX(tev_stage1.const_r): - SyncTevColor(1, regs.tev_stage1); - break; case PICA_REG_INDEX(tev_stage1.color_scale): - SyncTevMultipliers(1, regs.tev_stage1); - break; - - // TEV stage 2 case PICA_REG_INDEX(tev_stage2.color_source1): - SyncTevSources(2, regs.tev_stage2); - break; case PICA_REG_INDEX(tev_stage2.color_modifier1): - SyncTevModifiers(2, regs.tev_stage2); - break; case PICA_REG_INDEX(tev_stage2.color_op): - SyncTevOps(2, regs.tev_stage2); - break; - case PICA_REG_INDEX(tev_stage2.const_r): - SyncTevColor(2, regs.tev_stage2); - break; case PICA_REG_INDEX(tev_stage2.color_scale): - SyncTevMultipliers(2, regs.tev_stage2); - break; - - // TEV stage 3 case PICA_REG_INDEX(tev_stage3.color_source1): - SyncTevSources(3, regs.tev_stage3); - break; case PICA_REG_INDEX(tev_stage3.color_modifier1): - SyncTevModifiers(3, regs.tev_stage3); - break; case PICA_REG_INDEX(tev_stage3.color_op): - SyncTevOps(3, regs.tev_stage3); - break; - case PICA_REG_INDEX(tev_stage3.const_r): - SyncTevColor(3, regs.tev_stage3); - break; case PICA_REG_INDEX(tev_stage3.color_scale): - SyncTevMultipliers(3, regs.tev_stage3); - break; - - // TEV stage 4 case PICA_REG_INDEX(tev_stage4.color_source1): - SyncTevSources(4, regs.tev_stage4); - break; case PICA_REG_INDEX(tev_stage4.color_modifier1): - SyncTevModifiers(4, regs.tev_stage4); - break; case PICA_REG_INDEX(tev_stage4.color_op): - SyncTevOps(4, regs.tev_stage4); + case PICA_REG_INDEX(tev_stage4.color_scale): + case PICA_REG_INDEX(tev_stage5.color_source1): + case PICA_REG_INDEX(tev_stage5.color_modifier1): + case PICA_REG_INDEX(tev_stage5.color_op): + case PICA_REG_INDEX(tev_stage5.color_scale): + case PICA_REG_INDEX(tev_combiner_buffer_input): + state.draw.shader_dirty = true; break; - case PICA_REG_INDEX(tev_stage4.const_r): - SyncTevColor(4, regs.tev_stage4); + case PICA_REG_INDEX(tev_stage0.const_r): + SyncTevConstColor(0, regs.tev_stage0); break; - case PICA_REG_INDEX(tev_stage4.color_scale): - SyncTevMultipliers(4, regs.tev_stage4); + case PICA_REG_INDEX(tev_stage1.const_r): + SyncTevConstColor(1, regs.tev_stage0); break; - - // TEV stage 5 - case PICA_REG_INDEX(tev_stage5.color_source1): - SyncTevSources(5, regs.tev_stage5); + case PICA_REG_INDEX(tev_stage2.const_r): + SyncTevConstColor(2, regs.tev_stage0); break; - case PICA_REG_INDEX(tev_stage5.color_modifier1): - SyncTevModifiers(5, regs.tev_stage5); + case PICA_REG_INDEX(tev_stage3.const_r): + SyncTevConstColor(3, regs.tev_stage0); break; - case PICA_REG_INDEX(tev_stage5.color_op): - SyncTevOps(5, regs.tev_stage5); + case PICA_REG_INDEX(tev_stage4.const_r): + SyncTevConstColor(4, regs.tev_stage0); break; case PICA_REG_INDEX(tev_stage5.const_r): - SyncTevColor(5, regs.tev_stage5); - break; - case PICA_REG_INDEX(tev_stage5.color_scale): - SyncTevMultipliers(5, regs.tev_stage5); + SyncTevConstColor(5, regs.tev_stage0); break; // TEV combiner buffer color case PICA_REG_INDEX(tev_combiner_buffer_color): SyncCombinerColor(); break; - - // TEV combiner buffer write flags - case PICA_REG_INDEX(tev_combiner_buffer_input): - SyncCombinerWriteFlags(); - break; } } @@ -712,9 +654,8 @@ void RasterizerOpenGL::SyncBlendColor() { void RasterizerOpenGL::SyncAlphaTest() { const auto& regs = Pica::g_state.regs; - glUniform1i(uniform_alphatest_enabled, regs.output_merger.alpha_test.enable); - glUniform1i(uniform_alphatest_func, (GLint)regs.output_merger.alpha_test.func.Value()); - glUniform1f(uniform_alphatest_ref, regs.output_merger.alpha_test.ref / 255.0f); + if (current_shader->uniform_alphatest_ref != -1) + glUniform1f(current_shader->uniform_alphatest_ref, regs.output_merger.alpha_test.ref / 255.0f); } void RasterizerOpenGL::SyncLogicOp() { @@ -744,55 +685,17 @@ void RasterizerOpenGL::SyncDepthTest() { state.depth.write_mask = regs.output_merger.depth_write_enable ? GL_TRUE : GL_FALSE; } -void RasterizerOpenGL::SyncTevSources(unsigned stage_index, const Pica::Regs::TevStageConfig& config) { - GLint color_srcs[3] = { (GLint)config.color_source1.Value(), - (GLint)config.color_source2.Value(), - (GLint)config.color_source3.Value() }; - GLint alpha_srcs[3] = { (GLint)config.alpha_source1.Value(), - (GLint)config.alpha_source2.Value(), - (GLint)config.alpha_source3.Value() }; - - glUniform3iv(uniform_tev_cfgs[stage_index].color_sources, 1, color_srcs); - glUniform3iv(uniform_tev_cfgs[stage_index].alpha_sources, 1, alpha_srcs); -} - -void RasterizerOpenGL::SyncTevModifiers(unsigned stage_index, const Pica::Regs::TevStageConfig& config) { - GLint color_mods[3] = { (GLint)config.color_modifier1.Value(), - (GLint)config.color_modifier2.Value(), - (GLint)config.color_modifier3.Value() }; - GLint alpha_mods[3] = { (GLint)config.alpha_modifier1.Value(), - (GLint)config.alpha_modifier2.Value(), - (GLint)config.alpha_modifier3.Value() }; - - glUniform3iv(uniform_tev_cfgs[stage_index].color_modifiers, 1, color_mods); - glUniform3iv(uniform_tev_cfgs[stage_index].alpha_modifiers, 1, alpha_mods); -} - -void RasterizerOpenGL::SyncTevOps(unsigned stage_index, const Pica::Regs::TevStageConfig& config) { - glUniform2i(uniform_tev_cfgs[stage_index].color_alpha_op, (GLint)config.color_op.Value(), (GLint)config.alpha_op.Value()); -} - -void RasterizerOpenGL::SyncTevColor(unsigned stage_index, const Pica::Regs::TevStageConfig& config) { - auto const_color = PicaToGL::ColorRGBA8(config.const_color); - glUniform4fv(uniform_tev_cfgs[stage_index].const_color, 1, const_color.data()); -} - -void RasterizerOpenGL::SyncTevMultipliers(unsigned stage_index, const Pica::Regs::TevStageConfig& config) { - glUniform2i(uniform_tev_cfgs[stage_index].color_alpha_multiplier, config.GetColorMultiplier(), config.GetAlphaMultiplier()); -} - void RasterizerOpenGL::SyncCombinerColor() { - auto combiner_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.tev_combiner_buffer_color.raw); - glUniform4fv(uniform_tev_combiner_buffer_color, 1, combiner_color.data()); + if (current_shader->uniform_tev_combiner_buffer_color != -1) { + auto combiner_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.tev_combiner_buffer_color.raw); + glUniform4fv(current_shader->uniform_tev_combiner_buffer_color, 1, combiner_color.data()); + } } -void RasterizerOpenGL::SyncCombinerWriteFlags() { - const auto& regs = Pica::g_state.regs; - const auto tev_stages = regs.GetTevStages(); - for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); ++tev_stage_index) { - glUniform2i(uniform_tev_cfgs[tev_stage_index].updates_combiner_buffer_color_alpha, - regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor(tev_stage_index), - regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferAlpha(tev_stage_index)); +void RasterizerOpenGL::SyncTevConstColor(int stage_index, const Pica::Regs::TevStageConfig& tev_stage) { + if (current_shader->uniform_tev_const_colors != -1) { + auto const_color = PicaToGL::ColorRGBA8(tev_stage.const_color); + glUniform4fv(current_shader->uniform_tev_const_colors + stage_index, 1, const_color.data()); } } @@ -824,12 +727,6 @@ void RasterizerOpenGL::SyncDrawState() { } } - // Skip processing TEV stages that simply pass the previous stage results through - const auto tev_stages = regs.GetTevStages(); - for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); ++tev_stage_index) { - glUniform1i(uniform_tev_cfgs[tev_stage_index].enabled, !IsPassThroughTevStage(tev_stages[tev_stage_index])); - } - state.Apply(); } -- cgit v1.2.3 From 82f3e6dc69d23c3e70c1ad2805e2e15397cd9156 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 1 Oct 2015 18:34:10 -0400 Subject: gl_shader_util: Fix precision bug with alpha testing. - Alpha testing is not done with float32 precision, this makes the HW renderer match the SW renderer. --- src/video_core/renderer_opengl/gl_rasterizer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/video_core/renderer_opengl/gl_rasterizer.cpp') diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 45329d561..38d184ae2 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -195,7 +195,7 @@ void RasterizerOpenGL::RegenerateShaders() { // Sync alpha reference if (current_shader->uniform_alphatest_ref != -1) - glUniform1f(current_shader->uniform_alphatest_ref, regs.output_merger.alpha_test.ref / 255.0f); + glUniform1i(current_shader->uniform_alphatest_ref, regs.output_merger.alpha_test.ref); // Sync combiner buffer color if (current_shader->uniform_tev_combiner_buffer_color != -1) { @@ -655,7 +655,7 @@ void RasterizerOpenGL::SyncBlendColor() { void RasterizerOpenGL::SyncAlphaTest() { const auto& regs = Pica::g_state.regs; if (current_shader->uniform_alphatest_ref != -1) - glUniform1f(current_shader->uniform_alphatest_ref, regs.output_merger.alpha_test.ref / 255.0f); + glUniform1i(current_shader->uniform_alphatest_ref, regs.output_merger.alpha_test.ref); } void RasterizerOpenGL::SyncLogicOp() { -- cgit v1.2.3 From 37b0aa5af74dc01dadff5b173523580d03db2f02 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 1 Oct 2015 22:12:44 -0400 Subject: gl_rasterizer: Fix typo in uploading TEV const color uniforms. --- src/video_core/renderer_opengl/gl_rasterizer.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/video_core/renderer_opengl/gl_rasterizer.cpp') diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 38d184ae2..a69e09188 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -324,19 +324,19 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { SyncTevConstColor(0, regs.tev_stage0); break; case PICA_REG_INDEX(tev_stage1.const_r): - SyncTevConstColor(1, regs.tev_stage0); + SyncTevConstColor(1, regs.tev_stage1); break; case PICA_REG_INDEX(tev_stage2.const_r): - SyncTevConstColor(2, regs.tev_stage0); + SyncTevConstColor(2, regs.tev_stage2); break; case PICA_REG_INDEX(tev_stage3.const_r): - SyncTevConstColor(3, regs.tev_stage0); + SyncTevConstColor(3, regs.tev_stage3); break; case PICA_REG_INDEX(tev_stage4.const_r): - SyncTevConstColor(4, regs.tev_stage0); + SyncTevConstColor(4, regs.tev_stage4); break; case PICA_REG_INDEX(tev_stage5.const_r): - SyncTevConstColor(5, regs.tev_stage0); + SyncTevConstColor(5, regs.tev_stage5); break; // TEV combiner buffer color -- cgit v1.2.3 From 3c057bd3d80b049720b11d0b44391c18870c28e8 Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 5 Oct 2015 20:52:04 -0400 Subject: gl_rasterizer: Move logic for creating ShaderCacheKey to a static function. --- src/video_core/renderer_opengl/gl_rasterizer.cpp | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) (limited to 'src/video_core/renderer_opengl/gl_rasterizer.cpp') diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index a69e09188..01b9c91c6 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -145,21 +145,7 @@ extern std::string GenerateFragmentShader(const ShaderCacheKey& config); } void RasterizerOpenGL::RegenerateShaders() { - const auto& regs = Pica::g_state.regs; - - ShaderCacheKey config; - config.alpha_test_func = regs.output_merger.alpha_test.enable ? - regs.output_merger.alpha_test.func.Value() : Pica::Regs::CompareFunc::Always; - config.tev_stages = regs.GetTevStages(); - for (auto& tev : config.tev_stages) { - tev.const_r = 0; - tev.const_g = 0; - tev.const_b = 0; - tev.const_a = 0; - } - config.combiner_buffer_input = - regs.tev_combiner_buffer_input.update_mask_rgb.Value() | - regs.tev_combiner_buffer_input.update_mask_a.Value() << 4; + ShaderCacheKey config = ShaderCacheKey::CurrentShaderConfig(); auto cached_shader = shader_cache.find(config); if (cached_shader != shader_cache.end()) { @@ -192,10 +178,9 @@ void RasterizerOpenGL::RegenerateShaders() { } } - // Sync alpha reference if (current_shader->uniform_alphatest_ref != -1) - glUniform1i(current_shader->uniform_alphatest_ref, regs.output_merger.alpha_test.ref); + glUniform1i(current_shader->uniform_alphatest_ref, Pica::g_state.regs.output_merger.alpha_test.ref); // Sync combiner buffer color if (current_shader->uniform_tev_combiner_buffer_color != -1) { -- cgit v1.2.3 From c86b9d42423b5a83ccba40f828b7ad9dafe3e317 Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 5 Oct 2015 22:33:47 -0400 Subject: renderer_opengl: Refactor shader generation/caching to be more organized + various cleanups. --- src/video_core/renderer_opengl/gl_rasterizer.cpp | 131 ++++++++++------------- 1 file changed, 57 insertions(+), 74 deletions(-) (limited to 'src/video_core/renderer_opengl/gl_rasterizer.cpp') diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 01b9c91c6..4f9865230 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -9,6 +9,7 @@ #include "common/color.h" #include "common/file_util.h" +#include "common/make_unique.h" #include "common/math_util.h" #include "common/microprofile.h" #include "common/profiler.h" @@ -20,7 +21,7 @@ #include "video_core/pica.h" #include "video_core/utils.h" #include "video_core/renderer_opengl/gl_rasterizer.h" -#include "video_core/renderer_opengl/gl_shaders.h" +#include "video_core/renderer_opengl/gl_shader_gen.h" #include "video_core/renderer_opengl/gl_shader_util.h" #include "video_core/renderer_opengl/pica_to_gl.h" @@ -54,20 +55,20 @@ void RasterizerOpenGL::InitObjects() { state.Apply(); // Set vertex attributes - glVertexAttribPointer(ShaderUtil::ATTRIBUTE_POSITION, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, position)); - glEnableVertexAttribArray(ShaderUtil::ATTRIBUTE_POSITION); + glVertexAttribPointer(GLShader::ATTRIBUTE_POSITION, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, position)); + glEnableVertexAttribArray(GLShader::ATTRIBUTE_POSITION); - glVertexAttribPointer(ShaderUtil::ATTRIBUTE_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, color)); - glEnableVertexAttribArray(ShaderUtil::ATTRIBUTE_COLOR); + glVertexAttribPointer(GLShader::ATTRIBUTE_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, color)); + glEnableVertexAttribArray(GLShader::ATTRIBUTE_COLOR); - glVertexAttribPointer(ShaderUtil::ATTRIBUTE_TEXCOORDS, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0)); - glVertexAttribPointer(ShaderUtil::ATTRIBUTE_TEXCOORDS + 1, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord1)); - glVertexAttribPointer(ShaderUtil::ATTRIBUTE_TEXCOORDS + 2, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord2)); - glEnableVertexAttribArray(ShaderUtil::ATTRIBUTE_TEXCOORDS); - glEnableVertexAttribArray(ShaderUtil::ATTRIBUTE_TEXCOORDS + 1); - glEnableVertexAttribArray(ShaderUtil::ATTRIBUTE_TEXCOORDS + 2); + glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORDS + 0, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0)); + glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORDS + 1, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord1)); + glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORDS + 2, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord2)); + glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORDS + 0); + glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORDS + 1); + glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORDS + 2); - RegenerateShaders(); + SetShader(); // Create textures for OGL framebuffer that will be rendered to, initially 1x1 to succeed in framebuffer creation fb_color_texture.texture.Create(); @@ -117,8 +118,6 @@ void RasterizerOpenGL::InitObjects() { } void RasterizerOpenGL::Reset() { - const auto& regs = Pica::g_state.regs; - SyncCullMode(); SyncBlendEnabled(); SyncBlendFuncs(); @@ -127,7 +126,7 @@ void RasterizerOpenGL::Reset() { SyncStencilTest(); SyncDepthTest(); - RegenerateShaders(); + SetShader(); res_cache.FullFlush(); } @@ -140,70 +139,12 @@ void RasterizerOpenGL::AddTriangle(const Pica::Shader::OutputVertex& v0, vertex_batch.emplace_back(v2); } -namespace ShaderCache { -extern std::string GenerateFragmentShader(const ShaderCacheKey& config); -} - -void RasterizerOpenGL::RegenerateShaders() { - ShaderCacheKey config = ShaderCacheKey::CurrentShaderConfig(); - - auto cached_shader = shader_cache.find(config); - if (cached_shader != shader_cache.end()) { - current_shader = &cached_shader->second; - state.draw.shader_program = current_shader->shader.handle; - state.Apply(); - } else { - LOG_CRITICAL(Render_OpenGL, "Creating new shader: %08X", hash(config)); - - TEVShader shader; - - std::string fragShader = ShaderCache::GenerateFragmentShader(config); - shader.shader.Create(GLShaders::g_vertex_shader_hw, fragShader.c_str()); - - shader.uniform_alphatest_ref = glGetUniformLocation(shader.shader.handle, "alphatest_ref"); - shader.uniform_tex = glGetUniformLocation(shader.shader.handle, "tex"); - shader.uniform_tev_combiner_buffer_color = glGetUniformLocation(shader.shader.handle, "tev_combiner_buffer_color"); - shader.uniform_tev_const_colors = glGetUniformLocation(shader.shader.handle, "const_color"); - - current_shader = &shader_cache.emplace(config, std::move(shader)).first->second; - - state.draw.shader_program = current_shader->shader.handle; - state.Apply(); - - // Set the texture samplers to correspond to different texture units - if (shader.uniform_tex != -1) { - glUniform1i(shader.uniform_tex, 0); - glUniform1i(shader.uniform_tex + 1, 1); - glUniform1i(shader.uniform_tex + 2, 2); - } - } - - // Sync alpha reference - if (current_shader->uniform_alphatest_ref != -1) - glUniform1i(current_shader->uniform_alphatest_ref, Pica::g_state.regs.output_merger.alpha_test.ref); - - // Sync combiner buffer color - if (current_shader->uniform_tev_combiner_buffer_color != -1) { - auto combiner_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.tev_combiner_buffer_color.raw); - glUniform4fv(current_shader->uniform_tev_combiner_buffer_color, 1, combiner_color.data()); - } - - // Sync TEV const colors - if (current_shader->uniform_tev_const_colors != -1) { - auto& tev_stages = Pica::g_state.regs.GetTevStages(); - for (int tev_index = 0; tev_index < tev_stages.size(); ++tev_index) { - auto const_color = PicaToGL::ColorRGBA8(tev_stages[tev_index].const_color); - glUniform4fv(current_shader->uniform_tev_const_colors + tev_index, 1, const_color.data()); - } - } -} - void RasterizerOpenGL::DrawTriangles() { SyncFramebuffer(); SyncDrawState(); if (state.draw.shader_dirty) { - RegenerateShaders(); + SetShader(); state.draw.shader_dirty = false; } @@ -519,6 +460,48 @@ void RasterizerOpenGL::ReconfigureDepthTexture(DepthTextureInfo& texture, Pica:: state.Apply(); } +void RasterizerOpenGL::SetShader() { + ShaderCacheKey config = ShaderCacheKey::CurrentConfig(); + + // Find (or generate) the GLSL shader for the current TEV state + auto cached_shader = shader_cache.find(config); + if (cached_shader != shader_cache.end()) { + current_shader = cached_shader->second.get(); + + state.draw.shader_program = current_shader->shader.handle; + state.Apply(); + } else { + LOG_DEBUG(Render_OpenGL, "Creating new shader: %08X", hash(config)); + + std::unique_ptr shader = Common::make_unique(); + + shader->shader.Create(GLShader::GenerateVertexShader().c_str(), GLShader::GenerateFragmentShader(config).c_str()); + shader->uniform_alphatest_ref = glGetUniformLocation(shader->shader.handle, "alphatest_ref"); + shader->uniform_tex = glGetUniformLocation(shader->shader.handle, "tex"); + shader->uniform_tev_combiner_buffer_color = glGetUniformLocation(shader->shader.handle, "tev_combiner_buffer_color"); + shader->uniform_tev_const_colors = glGetUniformLocation(shader->shader.handle, "const_color"); + + state.draw.shader_program = shader->shader.handle; + state.Apply(); + + // Set the texture samplers to correspond to different texture units + if (shader->uniform_tex != -1) { + glUniform1i(shader->uniform_tex, 0); + glUniform1i(shader->uniform_tex + 1, 1); + glUniform1i(shader->uniform_tex + 2, 2); + } + + current_shader = shader_cache.emplace(config, std::move(shader)).first->second.get(); + } + + // Update uniforms + SyncAlphaTest(); + SyncCombinerColor(); + auto& tev_stages = Pica::g_state.regs.GetTevStages(); + for (int index = 0; index < tev_stages.size(); ++index) + SyncTevConstColor(index, tev_stages[index]); +} + void RasterizerOpenGL::SyncFramebuffer() { const auto& regs = Pica::g_state.regs; -- cgit v1.2.3 From 71edb55114af129d6f580e271ad5196043342abe Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 9 Oct 2015 19:32:38 -0400 Subject: gl_shader_gen: Require explicit uniform locations. - Fixes uniform issue on AMD. --- src/video_core/renderer_opengl/gl_rasterizer.cpp | 27 +++++++----------------- 1 file changed, 8 insertions(+), 19 deletions(-) (limited to 'src/video_core/renderer_opengl/gl_rasterizer.cpp') diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 4f9865230..64639ed26 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -476,20 +476,14 @@ void RasterizerOpenGL::SetShader() { std::unique_ptr shader = Common::make_unique(); shader->shader.Create(GLShader::GenerateVertexShader().c_str(), GLShader::GenerateFragmentShader(config).c_str()); - shader->uniform_alphatest_ref = glGetUniformLocation(shader->shader.handle, "alphatest_ref"); - shader->uniform_tex = glGetUniformLocation(shader->shader.handle, "tex"); - shader->uniform_tev_combiner_buffer_color = glGetUniformLocation(shader->shader.handle, "tev_combiner_buffer_color"); - shader->uniform_tev_const_colors = glGetUniformLocation(shader->shader.handle, "const_color"); state.draw.shader_program = shader->shader.handle; state.Apply(); // Set the texture samplers to correspond to different texture units - if (shader->uniform_tex != -1) { - glUniform1i(shader->uniform_tex, 0); - glUniform1i(shader->uniform_tex + 1, 1); - glUniform1i(shader->uniform_tex + 2, 2); - } + glUniform1i(PicaShader::Uniform::Texture0, 0); + glUniform1i(PicaShader::Uniform::Texture1, 1); + glUniform1i(PicaShader::Uniform::Texture2, 2); current_shader = shader_cache.emplace(config, std::move(shader)).first->second.get(); } @@ -622,8 +616,7 @@ void RasterizerOpenGL::SyncBlendColor() { void RasterizerOpenGL::SyncAlphaTest() { const auto& regs = Pica::g_state.regs; - if (current_shader->uniform_alphatest_ref != -1) - glUniform1i(current_shader->uniform_alphatest_ref, regs.output_merger.alpha_test.ref); + glUniform1i(PicaShader::Uniform::AlphaTestRef, regs.output_merger.alpha_test.ref); } void RasterizerOpenGL::SyncLogicOp() { @@ -654,17 +647,13 @@ void RasterizerOpenGL::SyncDepthTest() { } void RasterizerOpenGL::SyncCombinerColor() { - if (current_shader->uniform_tev_combiner_buffer_color != -1) { - auto combiner_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.tev_combiner_buffer_color.raw); - glUniform4fv(current_shader->uniform_tev_combiner_buffer_color, 1, combiner_color.data()); - } + auto combiner_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.tev_combiner_buffer_color.raw); + glUniform4fv(PicaShader::Uniform::TevCombinerBufferColor, 1, combiner_color.data()); } void RasterizerOpenGL::SyncTevConstColor(int stage_index, const Pica::Regs::TevStageConfig& tev_stage) { - if (current_shader->uniform_tev_const_colors != -1) { - auto const_color = PicaToGL::ColorRGBA8(tev_stage.const_color); - glUniform4fv(current_shader->uniform_tev_const_colors + stage_index, 1, const_color.data()); - } + auto const_color = PicaToGL::ColorRGBA8(tev_stage.const_color); + glUniform4fv(PicaShader::Uniform::TevConstColors + stage_index, 1, const_color.data()); } void RasterizerOpenGL::SyncDrawState() { -- cgit v1.2.3 From 240a3b80d970b56b4ed3671536489eb0e32532ae Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 9 Oct 2015 22:46:47 -0400 Subject: gl_rasterizer: Use MMH3 hash for shader cache hey. - Includes a check to confirm no hash collisions. --- src/video_core/renderer_opengl/gl_rasterizer.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src/video_core/renderer_opengl/gl_rasterizer.cpp') diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 64639ed26..4ae42f226 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -461,7 +461,8 @@ void RasterizerOpenGL::ReconfigureDepthTexture(DepthTextureInfo& texture, Pica:: } void RasterizerOpenGL::SetShader() { - ShaderCacheKey config = ShaderCacheKey::CurrentConfig(); + PicaShaderConfig config = PicaShaderConfig::CurrentConfig(); + std::unique_ptr shader = Common::make_unique(); // Find (or generate) the GLSL shader for the current TEV state auto cached_shader = shader_cache.find(config); @@ -471,9 +472,7 @@ void RasterizerOpenGL::SetShader() { state.draw.shader_program = current_shader->shader.handle; state.Apply(); } else { - LOG_DEBUG(Render_OpenGL, "Creating new shader: %08X", hash(config)); - - std::unique_ptr shader = Common::make_unique(); + LOG_DEBUG(Render_OpenGL, "Creating new shader"); shader->shader.Create(GLShader::GenerateVertexShader().c_str(), GLShader::GenerateFragmentShader(config).c_str()); -- cgit v1.2.3 From e7b1f2ae0af304abea3fb9a5b658abb92737caaa Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 21 Oct 2015 00:03:22 -0400 Subject: gl_rasterizer: Define enum types for each vertex texcoord attribute. --- src/video_core/renderer_opengl/gl_rasterizer.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/video_core/renderer_opengl/gl_rasterizer.cpp') diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 4ae42f226..d1def2f3b 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -61,12 +61,12 @@ void RasterizerOpenGL::InitObjects() { glVertexAttribPointer(GLShader::ATTRIBUTE_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, color)); glEnableVertexAttribArray(GLShader::ATTRIBUTE_COLOR); - glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORDS + 0, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0)); - glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORDS + 1, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord1)); - glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORDS + 2, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord2)); - glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORDS + 0); - glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORDS + 1); - glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORDS + 2); + glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD0, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0)); + glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD1, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord1)); + glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD2, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord2)); + glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD0); + glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD1); + glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD2); SetShader(); -- cgit v1.2.3