diff options
Diffstat (limited to '')
-rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 234 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 50 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | 285 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.h | 78 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_resource_manager.h | 114 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.cpp | 213 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_util.cpp | 3 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_state.cpp | 49 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_state.h | 40 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/pica_to_gl.h | 72 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 122 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.h | 15 |
12 files changed, 789 insertions, 486 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index f8393c618..5021f48bc 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -32,8 +32,7 @@ static bool IsPassThroughTevStage(const Pica::Regs::TevStageConfig& stage) { stage.alpha_source1 == Pica::Regs::TevStageConfig::Source::Previous && stage.color_modifier1 == Pica::Regs::TevStageConfig::ColorModifier::SourceColor && stage.alpha_modifier1 == Pica::Regs::TevStageConfig::AlphaModifier::SourceAlpha && - stage.GetColorMultiplier() == 1 && - stage.GetAlphaMultiplier() == 1); + stage.GetColorMultiplier() == 1 && stage.GetAlphaMultiplier() == 1); } RasterizerOpenGL::RasterizerOpenGL() : shader_dirty(true) { @@ -65,26 +64,34 @@ RasterizerOpenGL::RasterizerOpenGL() : shader_dirty(true) { uniform_block_data.fog_lut_dirty = true; // Set vertex attributes - glVertexAttribPointer(GLShader::ATTRIBUTE_POSITION, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, position)); + glVertexAttribPointer(GLShader::ATTRIBUTE_POSITION, 4, GL_FLOAT, GL_FALSE, + sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, position)); glEnableVertexAttribArray(GLShader::ATTRIBUTE_POSITION); - glVertexAttribPointer(GLShader::ATTRIBUTE_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, color)); + glVertexAttribPointer(GLShader::ATTRIBUTE_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), + (GLvoid*)offsetof(HardwareVertex, color)); glEnableVertexAttribArray(GLShader::ATTRIBUTE_COLOR); - 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)); + 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); - glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD0_W, 1, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0_w)); + glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD0_W, 1, GL_FLOAT, GL_FALSE, + sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0_w)); glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD0_W); - glVertexAttribPointer(GLShader::ATTRIBUTE_NORMQUAT, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, normquat)); + glVertexAttribPointer(GLShader::ATTRIBUTE_NORMQUAT, 4, GL_FLOAT, GL_FALSE, + sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, normquat)); glEnableVertexAttribArray(GLShader::ATTRIBUTE_NORMQUAT); - glVertexAttribPointer(GLShader::ATTRIBUTE_VIEW, 3, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, view)); + glVertexAttribPointer(GLShader::ATTRIBUTE_VIEW, 3, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), + (GLvoid*)offsetof(HardwareVertex, view)); glEnableVertexAttribArray(GLShader::ATTRIBUTE_VIEW); // Create render framebuffer @@ -130,7 +137,6 @@ RasterizerOpenGL::RasterizerOpenGL() : shader_dirty(true) { } RasterizerOpenGL::~RasterizerOpenGL() { - } /** @@ -149,8 +155,8 @@ RasterizerOpenGL::~RasterizerOpenGL() { * manually using two Lerps, and doing this correction before each Lerp. */ static bool AreQuaternionsOpposite(Math::Vec4<Pica::float24> qa, Math::Vec4<Pica::float24> qb) { - Math::Vec4f a{ qa.x.ToFloat32(), qa.y.ToFloat32(), qa.z.ToFloat32(), qa.w.ToFloat32() }; - Math::Vec4f b{ qb.x.ToFloat32(), qb.y.ToFloat32(), qb.z.ToFloat32(), qb.w.ToFloat32() }; + Math::Vec4f a{qa.x.ToFloat32(), qa.y.ToFloat32(), qa.z.ToFloat32(), qa.w.ToFloat32()}; + Math::Vec4f b{qb.x.ToFloat32(), qb.y.ToFloat32(), qb.z.ToFloat32(), qb.w.ToFloat32()}; return (Math::Dot(a, b) < 0.f); } @@ -173,15 +179,20 @@ void RasterizerOpenGL::DrawTriangles() { CachedSurface* color_surface; CachedSurface* depth_surface; MathUtil::Rectangle<int> rect; - std::tie(color_surface, depth_surface, rect) = res_cache.GetFramebufferSurfaces(regs.framebuffer); + std::tie(color_surface, depth_surface, rect) = + res_cache.GetFramebufferSurfaces(regs.framebuffer); state.draw.draw_framebuffer = framebuffer.handle; state.Apply(); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color_surface != nullptr ? color_surface->texture.handle : 0, 0); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_surface != nullptr ? depth_surface->texture.handle : 0, 0); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + color_surface != nullptr ? color_surface->texture.handle : 0, 0); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, + depth_surface != nullptr ? depth_surface->texture.handle : 0, 0); bool has_stencil = regs.framebuffer.depth_format == Pica::Regs::DepthFormat::D24S8; - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, (has_stencil && depth_surface != nullptr) ? depth_surface->texture.handle : 0, 0); + glFramebufferTexture2D( + GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, + (has_stencil && depth_surface != nullptr) ? depth_surface->texture.handle : 0, 0); if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { return; @@ -194,7 +205,8 @@ void RasterizerOpenGL::DrawTriangles() { glViewport((GLint)(rect.left + regs.viewport_corner.x * color_surface->res_scale_width), (GLint)(rect.bottom + regs.viewport_corner.y * color_surface->res_scale_height), - (GLsizei)(viewport_width * color_surface->res_scale_width), (GLsizei)(viewport_height * color_surface->res_scale_height)); + (GLsizei)(viewport_width * color_surface->res_scale_width), + (GLsizei)(viewport_height * color_surface->res_scale_height)); if (uniform_block_data.data.framebuffer_scale[0] != color_surface->res_scale_width || uniform_block_data.data.framebuffer_scale[1] != color_surface->res_scale_height) { @@ -245,14 +257,16 @@ void RasterizerOpenGL::DrawTriangles() { // Sync the uniform data if (uniform_block_data.dirty) { - glBufferData(GL_UNIFORM_BUFFER, sizeof(UniformData), &uniform_block_data.data, GL_STATIC_DRAW); + glBufferData(GL_UNIFORM_BUFFER, sizeof(UniformData), &uniform_block_data.data, + GL_STATIC_DRAW); uniform_block_data.dirty = false; } state.Apply(); // Draw the vertex batch - glBufferData(GL_ARRAY_BUFFER, vertex_batch.size() * sizeof(HardwareVertex), vertex_batch.data(), GL_STREAM_DRAW); + glBufferData(GL_ARRAY_BUFFER, vertex_batch.size() * sizeof(HardwareVertex), vertex_batch.data(), + GL_STREAM_DRAW); glDrawArrays(GL_TRIANGLES, 0, (GLsizei)vertex_batch.size()); // Mark framebuffer surfaces as dirty @@ -278,7 +292,7 @@ void RasterizerOpenGL::DrawTriangles() { void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { const auto& regs = Pica::g_state.regs; - switch(id) { + switch (id) { // Culling case PICA_REG_INDEX(cull_mode): SyncCullMode(); @@ -548,7 +562,7 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { SyncLightAmbient(7); break; - // Fragment lighting position + // Fragment lighting position case PICA_REG_INDEX_WORKAROUND(lighting.light[0].x, 0x144 + 0 * 0x10): case PICA_REG_INDEX_WORKAROUND(lighting.light[0].z, 0x145 + 0 * 0x10): SyncLightPosition(0); @@ -659,13 +673,11 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[4], 0x1cc): case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[5], 0x1cd): case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[6], 0x1ce): - case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[7], 0x1cf): - { + case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[7], 0x1cf): { auto& lut_config = regs.lighting.lut_config; uniform_block_data.lut_dirty[lut_config.type / 4] = true; break; } - } } @@ -699,8 +711,10 @@ bool RasterizerOpenGL::AccelerateDisplayTransfer(const GPU::Regs::DisplayTransfe CachedSurface dst_params; dst_params.addr = config.GetPhysicalOutputAddress(); - dst_params.width = config.scaling != config.NoScale ? config.output_width / 2 : config.output_width.Value(); - dst_params.height = config.scaling == config.ScaleXY ? config.output_height / 2 : config.output_height.Value(); + dst_params.width = + config.scaling != config.NoScale ? config.output_width / 2 : config.output_width.Value(); + dst_params.height = + config.scaling == config.ScaleXY ? config.output_height / 2 : config.output_height.Value(); dst_params.is_tiled = config.input_linear != config.dont_swizzle; dst_params.pixel_format = CachedSurface::PixelFormatFromGPUPixelFormat(config.output_format); @@ -735,7 +749,8 @@ bool RasterizerOpenGL::AccelerateDisplayTransfer(const GPU::Regs::DisplayTransfe return false; } - u32 dst_size = dst_params.width * dst_params.height * CachedSurface::GetFormatBpp(dst_params.pixel_format) / 8; + u32 dst_size = dst_params.width * dst_params.height * + CachedSurface::GetFormatBpp(dst_params.pixel_format) / 8; dst_surface->dirty = true; res_cache.FlushRegion(config.GetPhysicalOutputAddress(), dst_size, dst_surface, true); return true; @@ -757,12 +772,15 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config) GLuint old_fb = cur_state.draw.draw_framebuffer; cur_state.draw.draw_framebuffer = framebuffer.handle; - // TODO: When scissor test is implemented, need to disable scissor test in cur_state here so Clear call isn't affected + // TODO: When scissor test is implemented, need to disable scissor test in cur_state here so + // Clear call isn't affected cur_state.Apply(); if (dst_type == SurfaceType::Color || dst_type == SurfaceType::Texture) { - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dst_surface->texture.handle, 0); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + dst_surface->texture.handle, 0); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, + 0); if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { return false; @@ -770,8 +788,10 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config) GLfloat color_values[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - // TODO: Handle additional pixel format and fill value size combinations to accelerate more cases - // For instance, checking if fill value's bytes/bits repeat to allow filling I8/A8/I4/A4/... + // TODO: Handle additional pixel format and fill value size combinations to accelerate more + // cases + // For instance, checking if fill value's bytes/bits repeat to allow filling + // I8/A8/I4/A4/... // Currently only handles formats that are multiples of the fill value size if (config.fill_24bit) { @@ -846,7 +866,8 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config) glClearBufferfv(GL_COLOR, 0, color_values); } else if (dst_type == SurfaceType::Depth) { glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, dst_surface->texture.handle, 0); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, + dst_surface->texture.handle, 0); glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { @@ -865,7 +886,8 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config) glClearBufferfv(GL_DEPTH, 0, &value_float); } else if (dst_type == SurfaceType::DepthStencil) { glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, dst_surface->texture.handle, 0); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, + dst_surface->texture.handle, 0); if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { return false; @@ -889,7 +911,9 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config) return true; } -bool RasterizerOpenGL::AccelerateDisplay(const GPU::Regs::FramebufferConfig& config, PAddr framebuffer_addr, u32 pixel_stride, ScreenInfo& screen_info) { +bool RasterizerOpenGL::AccelerateDisplay(const GPU::Regs::FramebufferConfig& config, + PAddr framebuffer_addr, u32 pixel_stride, + ScreenInfo& screen_info) { if (framebuffer_addr == 0) { return false; } @@ -912,10 +936,9 @@ bool RasterizerOpenGL::AccelerateDisplay(const GPU::Regs::FramebufferConfig& con u32 scaled_width = src_surface->GetScaledWidth(); u32 scaled_height = src_surface->GetScaledHeight(); - screen_info.display_texcoords = MathUtil::Rectangle<float>((float)src_rect.top / (float)scaled_height, - (float)src_rect.left / (float)scaled_width, - (float)src_rect.bottom / (float)scaled_height, - (float)src_rect.right / (float)scaled_width); + screen_info.display_texcoords = MathUtil::Rectangle<float>( + (float)src_rect.top / (float)scaled_height, (float)src_rect.left / (float)scaled_width, + (float)src_rect.bottom / (float)scaled_height, (float)src_rect.right / (float)scaled_width); screen_info.display_texture = src_surface->texture.handle; @@ -928,7 +951,8 @@ void RasterizerOpenGL::SamplerInfo::Create() { wrap_s = wrap_t = TextureConfig::Repeat; border_color = 0; - glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // default is GL_LINEAR_MIPMAP_LINEAR + glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER, + GL_LINEAR); // default is GL_LINEAR_MIPMAP_LINEAR // Other attributes have correct defaults } @@ -976,41 +1000,64 @@ void RasterizerOpenGL::SetShader() { } else { LOG_DEBUG(Render_OpenGL, "Creating new shader"); - shader->shader.Create(GLShader::GenerateVertexShader().c_str(), GLShader::GenerateFragmentShader(config).c_str()); + shader->shader.Create(GLShader::GenerateVertexShader().c_str(), + GLShader::GenerateFragmentShader(config).c_str()); state.draw.shader_program = shader->shader.handle; state.Apply(); // Set the texture samplers to correspond to different texture units GLuint uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[0]"); - if (uniform_tex != -1) { glUniform1i(uniform_tex, 0); } + if (uniform_tex != -1) { + glUniform1i(uniform_tex, 0); + } uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[1]"); - if (uniform_tex != -1) { glUniform1i(uniform_tex, 1); } + if (uniform_tex != -1) { + glUniform1i(uniform_tex, 1); + } uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[2]"); - if (uniform_tex != -1) { glUniform1i(uniform_tex, 2); } + if (uniform_tex != -1) { + glUniform1i(uniform_tex, 2); + } // Set the texture samplers to correspond to different lookup table texture units GLuint uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[0]"); - if (uniform_lut != -1) { glUniform1i(uniform_lut, 3); } + if (uniform_lut != -1) { + glUniform1i(uniform_lut, 3); + } uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[1]"); - if (uniform_lut != -1) { glUniform1i(uniform_lut, 4); } + if (uniform_lut != -1) { + glUniform1i(uniform_lut, 4); + } uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[2]"); - if (uniform_lut != -1) { glUniform1i(uniform_lut, 5); } + if (uniform_lut != -1) { + glUniform1i(uniform_lut, 5); + } uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[3]"); - if (uniform_lut != -1) { glUniform1i(uniform_lut, 6); } + if (uniform_lut != -1) { + glUniform1i(uniform_lut, 6); + } uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[4]"); - if (uniform_lut != -1) { glUniform1i(uniform_lut, 7); } + if (uniform_lut != -1) { + glUniform1i(uniform_lut, 7); + } uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[5]"); - if (uniform_lut != -1) { glUniform1i(uniform_lut, 8); } + if (uniform_lut != -1) { + glUniform1i(uniform_lut, 8); + } GLuint uniform_fog_lut = glGetUniformLocation(shader->shader.handle, "fog_lut"); - if (uniform_fog_lut != -1) { glUniform1i(uniform_fog_lut, 9); } + if (uniform_fog_lut != -1) { + glUniform1i(uniform_fog_lut, 9); + } current_shader = shader_cache.emplace(config, std::move(shader)).first->second.get(); - unsigned int block_index = glGetUniformBlockIndex(current_shader->shader.handle, "shader_data"); + unsigned int block_index = + glGetUniformBlockIndex(current_shader->shader.handle, "shader_data"); GLint block_size; - glGetActiveUniformBlockiv(current_shader->shader.handle, block_index, GL_UNIFORM_BLOCK_DATA_SIZE, &block_size); + glGetActiveUniformBlockiv(current_shader->shader.handle, block_index, + GL_UNIFORM_BLOCK_DATA_SIZE, &block_size); ASSERT_MSG(block_size == sizeof(UniformData), "Uniform block size did not match!"); glUniformBlockBinding(current_shader->shader.handle, block_index, 0); @@ -1073,7 +1120,8 @@ void RasterizerOpenGL::SyncDepthScale() { } void RasterizerOpenGL::SyncDepthOffset() { - float depth_offset = Pica::float24::FromRaw(Pica::g_state.regs.viewport_depth_near_plane).ToFloat32(); + float depth_offset = + Pica::float24::FromRaw(Pica::g_state.regs.viewport_depth_near_plane).ToFloat32(); if (depth_offset != uniform_block_data.data.depth_offset) { uniform_block_data.data.depth_offset = depth_offset; uniform_block_data.dirty = true; @@ -1086,10 +1134,14 @@ void RasterizerOpenGL::SyncBlendEnabled() { void RasterizerOpenGL::SyncBlendFuncs() { const auto& regs = Pica::g_state.regs; - state.blend.rgb_equation = PicaToGL::BlendEquation(regs.output_merger.alpha_blending.blend_equation_rgb); - state.blend.a_equation = PicaToGL::BlendEquation(regs.output_merger.alpha_blending.blend_equation_a); - state.blend.src_rgb_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_rgb); - state.blend.dst_rgb_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_rgb); + state.blend.rgb_equation = + PicaToGL::BlendEquation(regs.output_merger.alpha_blending.blend_equation_rgb); + state.blend.a_equation = + PicaToGL::BlendEquation(regs.output_merger.alpha_blending.blend_equation_a); + state.blend.src_rgb_func = + PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_rgb); + state.blend.dst_rgb_func = + PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_rgb); state.blend.src_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_a); state.blend.dst_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_a); } @@ -1104,25 +1156,23 @@ void RasterizerOpenGL::SyncBlendColor() { void RasterizerOpenGL::SyncFogColor() { const auto& regs = Pica::g_state.regs; - uniform_block_data.data.fog_color = { - regs.fog_color.r.Value() / 255.0f, - regs.fog_color.g.Value() / 255.0f, - regs.fog_color.b.Value() / 255.0f - }; + uniform_block_data.data.fog_color = {regs.fog_color.r.Value() / 255.0f, + regs.fog_color.g.Value() / 255.0f, + regs.fog_color.b.Value() / 255.0f}; uniform_block_data.dirty = true; } void RasterizerOpenGL::SyncFogLUT() { std::array<GLuint, 128> new_data; - std::transform(Pica::g_state.fog.lut.begin(), Pica::g_state.fog.lut.end(), new_data.begin(), [](const auto& entry) { - return entry.raw; - }); + std::transform(Pica::g_state.fog.lut.begin(), Pica::g_state.fog.lut.end(), new_data.begin(), + [](const auto& entry) { return entry.raw; }); if (new_data != fog_lut_data) { fog_lut_data = new_data; glActiveTexture(GL_TEXTURE9); - glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 128, GL_RED_INTEGER, GL_UNSIGNED_INT, fog_lut_data.data()); + glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 128, GL_RED_INTEGER, GL_UNSIGNED_INT, + fog_lut_data.data()); } } @@ -1154,34 +1204,40 @@ void RasterizerOpenGL::SyncColorWriteMask() { void RasterizerOpenGL::SyncStencilWriteMask() { const auto& regs = Pica::g_state.regs; state.stencil.write_mask = (regs.framebuffer.allow_depth_stencil_write != 0) - ? static_cast<GLuint>(regs.output_merger.stencil_test.write_mask) - : 0; + ? static_cast<GLuint>(regs.output_merger.stencil_test.write_mask) + : 0; } void RasterizerOpenGL::SyncDepthWriteMask() { const auto& regs = Pica::g_state.regs; - state.depth.write_mask = (regs.framebuffer.allow_depth_stencil_write != 0 && regs.output_merger.depth_write_enable) - ? GL_TRUE - : GL_FALSE; + state.depth.write_mask = + (regs.framebuffer.allow_depth_stencil_write != 0 && regs.output_merger.depth_write_enable) + ? GL_TRUE + : GL_FALSE; } void RasterizerOpenGL::SyncStencilTest() { const auto& regs = Pica::g_state.regs; - state.stencil.test_enabled = regs.output_merger.stencil_test.enable && regs.framebuffer.depth_format == Pica::Regs::DepthFormat::D24S8; + state.stencil.test_enabled = regs.output_merger.stencil_test.enable && + regs.framebuffer.depth_format == Pica::Regs::DepthFormat::D24S8; state.stencil.test_func = PicaToGL::CompareFunc(regs.output_merger.stencil_test.func); state.stencil.test_ref = regs.output_merger.stencil_test.reference_value; state.stencil.test_mask = regs.output_merger.stencil_test.input_mask; - state.stencil.action_stencil_fail = PicaToGL::StencilOp(regs.output_merger.stencil_test.action_stencil_fail); - state.stencil.action_depth_fail = PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_fail); - state.stencil.action_depth_pass = PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_pass); + state.stencil.action_stencil_fail = + PicaToGL::StencilOp(regs.output_merger.stencil_test.action_stencil_fail); + state.stencil.action_depth_fail = + PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_fail); + state.stencil.action_depth_pass = + PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_pass); } void RasterizerOpenGL::SyncDepthTest() { const auto& regs = Pica::g_state.regs; - state.depth.test_enabled = regs.output_merger.depth_test_enable == 1 || - regs.output_merger.depth_write_enable == 1; - state.depth.test_func = regs.output_merger.depth_test_enable == 1 ? - PicaToGL::CompareFunc(regs.output_merger.depth_test_func) : GL_ALWAYS; + state.depth.test_enabled = + regs.output_merger.depth_test_enable == 1 || regs.output_merger.depth_write_enable == 1; + state.depth.test_func = regs.output_merger.depth_test_enable == 1 + ? PicaToGL::CompareFunc(regs.output_merger.depth_test_func) + : GL_ALWAYS; } void RasterizerOpenGL::SyncScissorTest() { @@ -1208,7 +1264,8 @@ void RasterizerOpenGL::SyncCombinerColor() { } } -void RasterizerOpenGL::SyncTevConstColor(int stage_index, const Pica::Regs::TevStageConfig& tev_stage) { +void RasterizerOpenGL::SyncTevConstColor(int stage_index, + const Pica::Regs::TevStageConfig& tev_stage) { auto const_color = PicaToGL::ColorRGBA8(tev_stage.const_color); if (const_color != uniform_block_data.data.const_color[stage_index]) { uniform_block_data.data.const_color[stage_index] = const_color; @@ -1237,7 +1294,8 @@ void RasterizerOpenGL::SyncLightingLUT(unsigned lut_index) { if (new_data != lighting_lut_data[lut_index]) { lighting_lut_data[lut_index] = new_data; glActiveTexture(GL_TEXTURE3 + lut_index); - glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 256, GL_RGBA, GL_FLOAT, lighting_lut_data[lut_index].data()); + glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 256, GL_RGBA, GL_FLOAT, + lighting_lut_data[lut_index].data()); } } @@ -1277,7 +1335,7 @@ void RasterizerOpenGL::SyncLightPosition(int light_index) { GLvec3 position = { Pica::float16::FromRaw(Pica::g_state.regs.lighting.light[light_index].x).ToFloat32(), Pica::float16::FromRaw(Pica::g_state.regs.lighting.light[light_index].y).ToFloat32(), - Pica::float16::FromRaw(Pica::g_state.regs.lighting.light[light_index].z).ToFloat32() }; + Pica::float16::FromRaw(Pica::g_state.regs.lighting.light[light_index].z).ToFloat32()}; if (position != uniform_block_data.data.light_src[light_index].position) { uniform_block_data.data.light_src[light_index].position = position; @@ -1286,7 +1344,9 @@ void RasterizerOpenGL::SyncLightPosition(int light_index) { } void RasterizerOpenGL::SyncLightDistanceAttenuationBias(int light_index) { - GLfloat dist_atten_bias = Pica::float20::FromRaw(Pica::g_state.regs.lighting.light[light_index].dist_atten_bias).ToFloat32(); + GLfloat dist_atten_bias = + Pica::float20::FromRaw(Pica::g_state.regs.lighting.light[light_index].dist_atten_bias) + .ToFloat32(); if (dist_atten_bias != uniform_block_data.data.light_src[light_index].dist_atten_bias) { uniform_block_data.data.light_src[light_index].dist_atten_bias = dist_atten_bias; @@ -1295,7 +1355,9 @@ void RasterizerOpenGL::SyncLightDistanceAttenuationBias(int light_index) { } void RasterizerOpenGL::SyncLightDistanceAttenuationScale(int light_index) { - GLfloat dist_atten_scale = Pica::float20::FromRaw(Pica::g_state.regs.lighting.light[light_index].dist_atten_scale).ToFloat32(); + GLfloat dist_atten_scale = + Pica::float20::FromRaw(Pica::g_state.regs.lighting.light[light_index].dist_atten_scale) + .ToFloat32(); if (dist_atten_scale != uniform_block_data.data.light_src[light_index].dist_atten_scale) { uniform_block_data.data.light_src[light_index].dist_atten_scale = dist_atten_scale; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index c5029432b..70e9e64ef 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -8,8 +8,8 @@ #include <cstddef> #include <cstring> #include <memory> -#include <vector> #include <unordered_map> +#include <vector> #include <glad/glad.h> @@ -40,10 +40,13 @@ struct ScreenInfo; * Pica state is not being captured in the shader cache key, thereby resulting in (what should be) * two separate shaders sharing the same key. * - * We use a union because "implicitly-defined copy/move constructor for a union X copies the object representation of X." - * and "implicitly-defined copy assignment operator for a union X copies the object representation (3.9) of X." + * We use a union because "implicitly-defined copy/move constructor for a union X copies the object + * representation of X." + * and "implicitly-defined copy assignment operator for a union X copies the object representation + * (3.9) of X." * = Bytewise copy instead of memberwise copy. - * This is important because the padding bytes are included in the hash and comparison between objects. + * This is important because the padding bytes are included in the hash and comparison between + * objects. */ union PicaShaderConfig { @@ -60,8 +63,9 @@ union PicaShaderConfig { state.depthmap_enable = regs.depthmap_enable; - state.alpha_test_func = regs.output_merger.alpha_test.enable ? - regs.output_merger.alpha_test.func.Value() : Pica::Regs::CompareFunc::Always; + state.alpha_test_func = regs.output_merger.alpha_test.enable + ? regs.output_merger.alpha_test.func.Value() + : Pica::Regs::CompareFunc::Always; state.texture0_type = regs.texture0.type; @@ -81,9 +85,8 @@ union PicaShaderConfig { state.fog_mode = regs.fog_mode; state.fog_flip = regs.fog_flip; - state.combiner_buffer_input = - regs.tev_combiner_buffer_input.update_mask_rgb.Value() | - regs.tev_combiner_buffer_input.update_mask_a.Value() << 4; + state.combiner_buffer_input = regs.tev_combiner_buffer_input.update_mask_rgb.Value() | + regs.tev_combiner_buffer_input.update_mask_a.Value() << 4; // Fragment lighting @@ -95,8 +98,10 @@ union PicaShaderConfig { const auto& light = regs.lighting.light[num]; state.lighting.light[light_index].num = num; state.lighting.light[light_index].directional = light.config.directional != 0; - state.lighting.light[light_index].two_sided_diffuse = light.config.two_sided_diffuse != 0; - state.lighting.light[light_index].dist_atten_enable = !regs.lighting.IsDistAttenDisabled(num); + state.lighting.light[light_index].two_sided_diffuse = + light.config.two_sided_diffuse != 0; + state.lighting.light[light_index].dist_atten_enable = + !regs.lighting.IsDistAttenDisabled(num); } state.lighting.lut_d0.enable = regs.lighting.config1.disable_lut_d0 == 0; @@ -147,7 +152,7 @@ union PicaShaderConfig { return (stage_index < 4) && ((state.combiner_buffer_input >> 4) & (1 << stage_index)); } - bool operator ==(const PicaShaderConfig& o) const { + bool operator==(const PicaShaderConfig& o) const { return std::memcmp(&state, &o.state, sizeof(PicaShaderConfig::State)) == 0; }; @@ -212,7 +217,8 @@ union PicaShaderConfig { } state; }; #if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER) -static_assert(std::is_trivially_copyable<PicaShaderConfig::State>::value, "PicaShaderConfig::State must be trivially copyable"); +static_assert(std::is_trivially_copyable<PicaShaderConfig::State>::value, + "PicaShaderConfig::State must be trivially copyable"); #endif namespace std { @@ -228,12 +234,10 @@ struct hash<PicaShaderConfig> { class RasterizerOpenGL : public VideoCore::RasterizerInterface { public: - RasterizerOpenGL(); ~RasterizerOpenGL() override; - void AddTriangle(const Pica::Shader::OutputVertex& v0, - const Pica::Shader::OutputVertex& v1, + void AddTriangle(const Pica::Shader::OutputVertex& v0, const Pica::Shader::OutputVertex& v1, const Pica::Shader::OutputVertex& v2) override; void DrawTriangles() override; void NotifyPicaRegisterChanged(u32 id) override; @@ -242,7 +246,8 @@ public: void FlushAndInvalidateRegion(PAddr addr, u32 size) override; bool AccelerateDisplayTransfer(const GPU::Regs::DisplayTransferConfig& config) override; bool AccelerateFill(const GPU::Regs::MemoryFillConfig& config) override; - bool AccelerateDisplay(const GPU::Regs::FramebufferConfig& config, PAddr framebuffer_addr, u32 pixel_stride, ScreenInfo& screen_info) override; + bool AccelerateDisplay(const GPU::Regs::FramebufferConfig& config, PAddr framebuffer_addr, + u32 pixel_stride, ScreenInfo& screen_info) override; /// OpenGL shader generated for a given Pica register state struct PicaShader { @@ -251,13 +256,13 @@ public: }; private: - struct SamplerInfo { using TextureConfig = Pica::Regs::TextureConfig; OGLSampler sampler; - /// Creates the sampler object, initializing its state so that it's in sync with the SamplerInfo struct. + /// Creates the sampler object, initializing its state so that it's in sync with the + /// SamplerInfo struct. void Create(); /// Syncs the sampler object with the config, updating any necessary state. void SyncWithConfig(const TextureConfig& config); @@ -343,8 +348,11 @@ private: alignas(16) GLvec4 tev_combiner_buffer_color; }; - static_assert(sizeof(UniformData) == 0x3C0, "The size of the UniformData structure has changed, update the structure in the shader"); - static_assert(sizeof(UniformData) < 16384, "UniformData structure must be less than 16kb as per the OpenGL spec"); + static_assert( + sizeof(UniformData) == 0x3C0, + "The size of the UniformData structure has changed, update the structure in the shader"); + static_assert(sizeof(UniformData) < 16384, + "UniformData structure must be less than 16kb as per the OpenGL spec"); /// Sets the OpenGL shader in accordance with the current PICA register state void SetShader(); diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 7efd0038a..8f1477bcd 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -35,18 +35,18 @@ struct FormatTuple { }; static const std::array<FormatTuple, 5> fb_format_tuples = {{ - { GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8 }, // RGBA8 - { GL_RGB8, GL_BGR, GL_UNSIGNED_BYTE }, // RGB8 - { GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 }, // RGB5A1 - { GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 }, // RGB565 - { GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 }, // RGBA4 + {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8}, // RGBA8 + {GL_RGB8, GL_BGR, GL_UNSIGNED_BYTE}, // RGB8 + {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1}, // RGB5A1 + {GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}, // RGB565 + {GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4}, // RGBA4 }}; static const std::array<FormatTuple, 4> depth_format_tuples = {{ - { GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT }, // D16 + {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}, // D16 {}, - { GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT }, // D24 - { GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8 }, // D24S8 + {GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT}, // D24 + {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // D24S8 }}; RasterizerCacheOpenGL::RasterizerCacheOpenGL() { @@ -58,7 +58,9 @@ RasterizerCacheOpenGL::~RasterizerCacheOpenGL() { FlushAll(); } -static void MortonCopyPixels(CachedSurface::PixelFormat pixel_format, u32 width, u32 height, u32 bytes_per_pixel, u32 gl_bytes_per_pixel, u8* morton_data, u8* gl_data, bool morton_to_gl) { +static void MortonCopyPixels(CachedSurface::PixelFormat pixel_format, u32 width, u32 height, + u32 bytes_per_pixel, u32 gl_bytes_per_pixel, u8* morton_data, + u8* gl_data, bool morton_to_gl) { using PixelFormat = CachedSurface::PixelFormat; u8* data_ptrs[2]; @@ -72,7 +74,8 @@ static void MortonCopyPixels(CachedSurface::PixelFormat pixel_format, u32 width, for (unsigned y = 0; y < height; ++y) { for (unsigned x = 0; x < width; ++x) { const u32 coarse_y = y & ~7; - u32 morton_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * width * bytes_per_pixel; + u32 morton_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + + coarse_y * width * bytes_per_pixel; u32 gl_pixel_index = (x + (height - 1 - y) * width) * gl_bytes_per_pixel; data_ptrs[morton_to_gl] = morton_data + morton_offset; @@ -81,7 +84,8 @@ static void MortonCopyPixels(CachedSurface::PixelFormat pixel_format, u32 width, // Swap depth and stencil value ordering since 3DS does not match OpenGL u32 depth_stencil; memcpy(&depth_stencil, data_ptrs[1], sizeof(u32)); - depth_stencil = (depth_stencil << depth_stencil_shifts[0]) | (depth_stencil >> depth_stencil_shifts[1]); + depth_stencil = (depth_stencil << depth_stencil_shifts[0]) | + (depth_stencil >> depth_stencil_shifts[1]); memcpy(data_ptrs[0], &depth_stencil, sizeof(u32)); } @@ -90,7 +94,8 @@ static void MortonCopyPixels(CachedSurface::PixelFormat pixel_format, u32 width, for (unsigned y = 0; y < height; ++y) { for (unsigned x = 0; x < width; ++x) { const u32 coarse_y = y & ~7; - u32 morton_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * width * bytes_per_pixel; + u32 morton_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + + coarse_y * width * bytes_per_pixel; u32 gl_pixel_index = (x + (height - 1 - y) * width) * gl_bytes_per_pixel; data_ptrs[morton_to_gl] = morton_data + morton_offset; @@ -102,17 +107,21 @@ static void MortonCopyPixels(CachedSurface::PixelFormat pixel_format, u32 width, } } -bool RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex, CachedSurface::SurfaceType type, const MathUtil::Rectangle<int>& src_rect, const MathUtil::Rectangle<int>& dst_rect) { +bool RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex, + CachedSurface::SurfaceType type, + const MathUtil::Rectangle<int>& src_rect, + const MathUtil::Rectangle<int>& dst_rect) { using SurfaceType = CachedSurface::SurfaceType; OpenGLState cur_state = OpenGLState::GetCurState(); - // Make sure textures aren't bound to texture units, since going to bind them to framebuffer components + // Make sure textures aren't bound to texture units, since going to bind them to framebuffer + // components OpenGLState::ResetTexture(src_tex); OpenGLState::ResetTexture(dst_tex); // Keep track of previous framebuffer bindings - GLuint old_fbs[2] = { cur_state.draw.read_framebuffer, cur_state.draw.draw_framebuffer }; + GLuint old_fbs[2] = {cur_state.draw.read_framebuffer, cur_state.draw.draw_framebuffer}; cur_state.draw.read_framebuffer = transfer_framebuffers[0].handle; cur_state.draw.draw_framebuffer = transfer_framebuffers[1].handle; cur_state.Apply(); @@ -120,11 +129,15 @@ bool RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex, CachedS u32 buffers = 0; if (type == SurfaceType::Color || type == SurfaceType::Texture) { - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, src_tex, 0); - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, src_tex, + 0); + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, + 0); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dst_tex, 0); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dst_tex, + 0); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, + 0); buffers = GL_COLOR_BUFFER_BIT; } else if (type == SurfaceType::Depth) { @@ -139,10 +152,12 @@ bool RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex, CachedS buffers = GL_DEPTH_BUFFER_BIT; } else if (type == SurfaceType::DepthStencil) { glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, src_tex, 0); + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, + src_tex, 0); glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, dst_tex, 0); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, + dst_tex, 0); buffers = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; } @@ -155,9 +170,9 @@ bool RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex, CachedS return false; } - glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom, - dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, - buffers, buffers == GL_COLOR_BUFFER_BIT ? GL_LINEAR : GL_NEAREST); + glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom, dst_rect.left, + dst_rect.top, dst_rect.right, dst_rect.bottom, buffers, + buffers == GL_COLOR_BUFFER_BIT ? GL_LINEAR : GL_NEAREST); // Restore previous framebuffer bindings cur_state.draw.read_framebuffer = old_fbs[0]; @@ -167,17 +182,24 @@ bool RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex, CachedS return true; } -bool RasterizerCacheOpenGL::TryBlitSurfaces(CachedSurface* src_surface, const MathUtil::Rectangle<int>& src_rect, CachedSurface* dst_surface, const MathUtil::Rectangle<int>& dst_rect) { +bool RasterizerCacheOpenGL::TryBlitSurfaces(CachedSurface* src_surface, + const MathUtil::Rectangle<int>& src_rect, + CachedSurface* dst_surface, + const MathUtil::Rectangle<int>& dst_rect) { using SurfaceType = CachedSurface::SurfaceType; - if (!CachedSurface::CheckFormatsBlittable(src_surface->pixel_format, dst_surface->pixel_format)) { + if (!CachedSurface::CheckFormatsBlittable(src_surface->pixel_format, + dst_surface->pixel_format)) { return false; } - return BlitTextures(src_surface->texture.handle, dst_surface->texture.handle, CachedSurface::GetFormatType(src_surface->pixel_format), src_rect, dst_rect); + return BlitTextures(src_surface->texture.handle, dst_surface->texture.handle, + CachedSurface::GetFormatType(src_surface->pixel_format), src_rect, + dst_rect); } -static void AllocateSurfaceTexture(GLuint texture, CachedSurface::PixelFormat pixel_format, u32 width, u32 height) { +static void AllocateSurfaceTexture(GLuint texture, CachedSurface::PixelFormat pixel_format, + u32 width, u32 height) { // Allocate an uninitialized texture of appropriate size and format for the surface using SurfaceType = CachedSurface::SurfaceType; @@ -200,11 +222,11 @@ static void AllocateSurfaceTexture(GLuint texture, CachedSurface::PixelFormat pi ASSERT(tuple_idx < depth_format_tuples.size()); tuple = depth_format_tuples[tuple_idx]; } else { - tuple = { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE }; + tuple = {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}; } - glTexImage2D(GL_TEXTURE_2D, 0, tuple.internal_format, width, height, 0, - tuple.format, tuple.type, nullptr); + glTexImage2D(GL_TEXTURE_2D, 0, tuple.internal_format, width, height, 0, tuple.format, + tuple.type, nullptr); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -217,7 +239,8 @@ static void AllocateSurfaceTexture(GLuint texture, CachedSurface::PixelFormat pi } MICROPROFILE_DEFINE(OpenGL_SurfaceUpload, "OpenGL", "Surface Upload", MP_RGB(128, 64, 192)); -CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bool match_res_scale, bool load_if_create) { +CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bool match_res_scale, + bool load_if_create) { using PixelFormat = CachedSurface::PixelFormat; using SurfaceType = CachedSurface::SurfaceType; @@ -225,29 +248,31 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo return nullptr; } - u32 params_size = params.width * params.height * CachedSurface::GetFormatBpp(params.pixel_format) / 8; + u32 params_size = + params.width * params.height * CachedSurface::GetFormatBpp(params.pixel_format) / 8; // Check for an exact match in existing surfaces CachedSurface* best_exact_surface = nullptr; float exact_surface_goodness = -1.f; - auto surface_interval = boost::icl::interval<PAddr>::right_open(params.addr, params.addr + params_size); + auto surface_interval = + boost::icl::interval<PAddr>::right_open(params.addr, params.addr + params_size); auto range = surface_cache.equal_range(surface_interval); for (auto it = range.first; it != range.second; ++it) { for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2) { CachedSurface* surface = it2->get(); // Check if the request matches the surface exactly - if (params.addr == surface->addr && - params.width == surface->width && params.height == surface->height && - params.pixel_format == surface->pixel_format) - { + if (params.addr == surface->addr && params.width == surface->width && + params.height == surface->height && params.pixel_format == surface->pixel_format) { // Make sure optional param-matching criteria are fulfilled bool tiling_match = (params.is_tiled == surface->is_tiled); - bool res_scale_match = (params.res_scale_width == surface->res_scale_width && params.res_scale_height == surface->res_scale_height); + bool res_scale_match = (params.res_scale_width == surface->res_scale_width && + params.res_scale_height == surface->res_scale_height); if (!match_res_scale || res_scale_match) { // Prioritize same-tiling and highest resolution surfaces - float match_goodness = (float)tiling_match + surface->res_scale_width * surface->res_scale_height; + float match_goodness = + (float)tiling_match + surface->res_scale_width * surface->res_scale_height; if (match_goodness > exact_surface_goodness || surface->dirty) { exact_surface_goodness = match_goodness; best_exact_surface = surface; @@ -288,9 +313,11 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo if (!load_if_create) { // Don't load any data; just allocate the surface's texture - AllocateSurfaceTexture(new_surface->texture.handle, new_surface->pixel_format, new_surface->GetScaledWidth(), new_surface->GetScaledHeight()); + AllocateSurfaceTexture(new_surface->texture.handle, new_surface->pixel_format, + new_surface->GetScaledWidth(), new_surface->GetScaledHeight()); } else { - // TODO: Consider attempting subrect match in existing surfaces and direct blit here instead of memory upload below if that's a common scenario in some game + // TODO: Consider attempting subrect match in existing surfaces and direct blit here instead + // of memory upload below if that's a common scenario in some game Memory::RasterizerFlushRegion(params.addr, params_size); @@ -318,7 +345,7 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo tuple = fb_format_tuples[(unsigned int)params.pixel_format]; } else { // Texture - tuple = { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE }; + tuple = {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}; } std::vector<Math::Vec4<u8>> tex_buffer(params.width * params.height); @@ -326,19 +353,23 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo Pica::DebugUtils::TextureInfo tex_info; tex_info.width = params.width; tex_info.height = params.height; - tex_info.stride = params.width * CachedSurface::GetFormatBpp(params.pixel_format) / 8; + tex_info.stride = + params.width * CachedSurface::GetFormatBpp(params.pixel_format) / 8; tex_info.format = (Pica::Regs::TextureFormat)params.pixel_format; tex_info.physical_address = params.addr; for (unsigned y = 0; y < params.height; ++y) { for (unsigned x = 0; x < params.width; ++x) { - tex_buffer[x + params.width * y] = Pica::DebugUtils::LookupTexture(texture_src_data, x, params.height - 1 - y, tex_info); + tex_buffer[x + params.width * y] = Pica::DebugUtils::LookupTexture( + texture_src_data, x, params.height - 1 - y, tex_info); } } - glTexImage2D(GL_TEXTURE_2D, 0, tuple.internal_format, params.width, params.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex_buffer.data()); + glTexImage2D(GL_TEXTURE_2D, 0, tuple.internal_format, params.width, params.height, + 0, GL_RGBA, GL_UNSIGNED_BYTE, tex_buffer.data()); } else { - // Depth/Stencil formats need special treatment since they aren't sampleable using LookupTexture and can't use RGBA format + // Depth/Stencil formats need special treatment since they aren't sampleable using + // LookupTexture and can't use RGBA format size_t tuple_idx = (size_t)params.pixel_format - 14; ASSERT(tuple_idx < depth_format_tuples.size()); const FormatTuple& tuple = depth_format_tuples[tuple_idx]; @@ -350,14 +381,18 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo u32 gl_bytes_per_pixel = use_4bpp ? 4 : bytes_per_pixel; - std::vector<u8> temp_fb_depth_buffer(params.width * params.height * gl_bytes_per_pixel); + std::vector<u8> temp_fb_depth_buffer(params.width * params.height * + gl_bytes_per_pixel); - u8* temp_fb_depth_buffer_ptr = use_4bpp ? temp_fb_depth_buffer.data() + 1 : temp_fb_depth_buffer.data(); + u8* temp_fb_depth_buffer_ptr = + use_4bpp ? temp_fb_depth_buffer.data() + 1 : temp_fb_depth_buffer.data(); - MortonCopyPixels(params.pixel_format, params.width, params.height, bytes_per_pixel, gl_bytes_per_pixel, texture_src_data, temp_fb_depth_buffer_ptr, true); + MortonCopyPixels(params.pixel_format, params.width, params.height, bytes_per_pixel, + gl_bytes_per_pixel, texture_src_data, temp_fb_depth_buffer_ptr, + true); - glTexImage2D(GL_TEXTURE_2D, 0, tuple.internal_format, params.width, params.height, 0, - tuple.format, tuple.type, temp_fb_depth_buffer.data()); + glTexImage2D(GL_TEXTURE_2D, 0, tuple.internal_format, params.width, params.height, + 0, tuple.format, tuple.type, temp_fb_depth_buffer.data()); } } glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); @@ -367,10 +402,13 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo OGLTexture scaled_texture; scaled_texture.Create(); - AllocateSurfaceTexture(scaled_texture.handle, new_surface->pixel_format, new_surface->GetScaledWidth(), new_surface->GetScaledHeight()); - BlitTextures(new_surface->texture.handle, scaled_texture.handle, CachedSurface::GetFormatType(new_surface->pixel_format), - MathUtil::Rectangle<int>(0, 0, new_surface->width, new_surface->height), - MathUtil::Rectangle<int>(0, 0, new_surface->GetScaledWidth(), new_surface->GetScaledHeight())); + AllocateSurfaceTexture(scaled_texture.handle, new_surface->pixel_format, + new_surface->GetScaledWidth(), new_surface->GetScaledHeight()); + BlitTextures(new_surface->texture.handle, scaled_texture.handle, + CachedSurface::GetFormatType(new_surface->pixel_format), + MathUtil::Rectangle<int>(0, 0, new_surface->width, new_surface->height), + MathUtil::Rectangle<int>(0, 0, new_surface->GetScaledWidth(), + new_surface->GetScaledHeight())); new_surface->texture.Release(); new_surface->texture.handle = scaled_texture.handle; @@ -389,11 +427,15 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo } Memory::RasterizerMarkRegionCached(new_surface->addr, new_surface->size, 1); - surface_cache.add(std::make_pair(boost::icl::interval<PAddr>::right_open(new_surface->addr, new_surface->addr + new_surface->size), std::set<std::shared_ptr<CachedSurface>>({ new_surface }))); + surface_cache.add(std::make_pair(boost::icl::interval<PAddr>::right_open( + new_surface->addr, new_surface->addr + new_surface->size), + std::set<std::shared_ptr<CachedSurface>>({new_surface}))); return new_surface.get(); } -CachedSurface* RasterizerCacheOpenGL::GetSurfaceRect(const CachedSurface& params, bool match_res_scale, bool load_if_create, MathUtil::Rectangle<int>& out_rect) { +CachedSurface* RasterizerCacheOpenGL::GetSurfaceRect(const CachedSurface& params, + bool match_res_scale, bool load_if_create, + MathUtil::Rectangle<int>& out_rect) { if (params.addr == 0) { return nullptr; } @@ -405,7 +447,8 @@ CachedSurface* RasterizerCacheOpenGL::GetSurfaceRect(const CachedSurface& params CachedSurface* best_subrect_surface = nullptr; float subrect_surface_goodness = -1.f; - auto surface_interval = boost::icl::interval<PAddr>::right_open(params.addr, params.addr + params_size); + auto surface_interval = + boost::icl::interval<PAddr>::right_open(params.addr, params.addr + params_size); auto cache_upper_bound = surface_cache.upper_bound(surface_interval); for (auto it = surface_cache.lower_bound(surface_interval); it != cache_upper_bound; ++it) { for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2) { @@ -414,14 +457,15 @@ CachedSurface* RasterizerCacheOpenGL::GetSurfaceRect(const CachedSurface& params // Check if the request is contained in the surface if (params.addr >= surface->addr && params.addr + params_size - 1 <= surface->addr + surface->size - 1 && - params.pixel_format == surface->pixel_format) - { + params.pixel_format == surface->pixel_format) { // Make sure optional param-matching criteria are fulfilled bool tiling_match = (params.is_tiled == surface->is_tiled); - bool res_scale_match = (params.res_scale_width == surface->res_scale_width && params.res_scale_height == surface->res_scale_height); + bool res_scale_match = (params.res_scale_width == surface->res_scale_width && + params.res_scale_height == surface->res_scale_height); if (!match_res_scale || res_scale_match) { // Prioritize same-tiling and highest resolution surfaces - float match_goodness = (float)tiling_match + surface->res_scale_width * surface->res_scale_height; + float match_goodness = + (float)tiling_match + surface->res_scale_width * surface->res_scale_height; if (match_goodness > subrect_surface_goodness || surface->dirty) { subrect_surface_goodness = match_goodness; best_subrect_surface = surface; @@ -433,7 +477,8 @@ CachedSurface* RasterizerCacheOpenGL::GetSurfaceRect(const CachedSurface& params // Return the best subrect surface if found if (best_subrect_surface != nullptr) { - unsigned int bytes_per_pixel = (CachedSurface::GetFormatBpp(best_subrect_surface->pixel_format) / 8); + unsigned int bytes_per_pixel = + (CachedSurface::GetFormatBpp(best_subrect_surface->pixel_format) / 8); int x0, y0; @@ -452,7 +497,9 @@ CachedSurface* RasterizerCacheOpenGL::GetSurfaceRect(const CachedSurface& params y0 = begin_tile_index / tiles_per_row * 8; // Tiled surfaces are flipped vertically in the rasterizer vs. 3DS memory. - out_rect = MathUtil::Rectangle<int>(x0, best_subrect_surface->height - y0, x0 + params.width, best_subrect_surface->height - (y0 + params.height)); + out_rect = + MathUtil::Rectangle<int>(x0, best_subrect_surface->height - y0, x0 + params.width, + best_subrect_surface->height - (y0 + params.height)); } out_rect.left = (int)(out_rect.left * best_subrect_surface->res_scale_width); @@ -465,16 +512,20 @@ CachedSurface* RasterizerCacheOpenGL::GetSurfaceRect(const CachedSurface& params // No subrect found - create and return a new surface if (!params.is_tiled) { - out_rect = MathUtil::Rectangle<int>(0, 0, (int)(params.width * params.res_scale_width), (int)(params.height * params.res_scale_height)); + out_rect = MathUtil::Rectangle<int>(0, 0, (int)(params.width * params.res_scale_width), + (int)(params.height * params.res_scale_height)); } else { - out_rect = MathUtil::Rectangle<int>(0, (int)(params.height * params.res_scale_height), (int)(params.width * params.res_scale_width), 0); + out_rect = MathUtil::Rectangle<int>(0, (int)(params.height * params.res_scale_height), + (int)(params.width * params.res_scale_width), 0); } return GetSurface(params, match_res_scale, load_if_create); } -CachedSurface* RasterizerCacheOpenGL::GetTextureSurface(const Pica::Regs::FullTextureConfig& config) { - Pica::DebugUtils::TextureInfo info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config.config, config.format); +CachedSurface* +RasterizerCacheOpenGL::GetTextureSurface(const Pica::Regs::FullTextureConfig& config) { + Pica::DebugUtils::TextureInfo info = + Pica::DebugUtils::TextureInfo::FromPicaRegister(config.config, config.format); CachedSurface params; params.addr = info.physical_address; @@ -485,20 +536,28 @@ CachedSurface* RasterizerCacheOpenGL::GetTextureSurface(const Pica::Regs::FullTe return GetSurface(params, false, true); } -std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> RasterizerCacheOpenGL::GetFramebufferSurfaces(const Pica::Regs::FramebufferConfig& config) { +std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> +RasterizerCacheOpenGL::GetFramebufferSurfaces(const Pica::Regs::FramebufferConfig& config) { const auto& regs = Pica::g_state.regs; // Make sur that framebuffers don't overlap if both color and depth are being used u32 fb_area = config.GetWidth() * config.GetHeight(); - bool framebuffers_overlap = config.GetColorBufferPhysicalAddress() != 0 && - config.GetDepthBufferPhysicalAddress() != 0 && - MathUtil::IntervalsIntersect(config.GetColorBufferPhysicalAddress(), fb_area * GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(config.color_format.Value())), - config.GetDepthBufferPhysicalAddress(), fb_area * Pica::Regs::BytesPerDepthPixel(config.depth_format)); + bool framebuffers_overlap = + config.GetColorBufferPhysicalAddress() != 0 && + config.GetDepthBufferPhysicalAddress() != 0 && + MathUtil::IntervalsIntersect( + config.GetColorBufferPhysicalAddress(), + fb_area * GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(config.color_format.Value())), + config.GetDepthBufferPhysicalAddress(), + fb_area * Pica::Regs::BytesPerDepthPixel(config.depth_format)); bool using_color_fb = config.GetColorBufferPhysicalAddress() != 0; - bool using_depth_fb = config.GetDepthBufferPhysicalAddress() != 0 && (regs.output_merger.depth_test_enable || regs.output_merger.depth_write_enable || !framebuffers_overlap); + bool using_depth_fb = config.GetDepthBufferPhysicalAddress() != 0 && + (regs.output_merger.depth_test_enable || + regs.output_merger.depth_write_enable || !framebuffers_overlap); if (framebuffers_overlap && using_color_fb && using_depth_fb) { - LOG_CRITICAL(Render_OpenGL, "Color and depth framebuffer memory regions overlap; overlapping framebuffers not supported!"); + LOG_CRITICAL(Render_OpenGL, "Color and depth framebuffer memory regions overlap; " + "overlapping framebuffers not supported!"); using_depth_fb = false; } @@ -512,8 +571,10 @@ std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> RasterizerC auto layout = VideoCore::g_emu_window->GetFramebufferLayout(); // Assume same scaling factor for top and bottom screens - color_params.res_scale_width = depth_params.res_scale_width = (float)layout.top_screen.GetWidth() / VideoCore::kScreenTopWidth; - color_params.res_scale_height = depth_params.res_scale_height = (float)layout.top_screen.GetHeight() / VideoCore::kScreenTopHeight; + color_params.res_scale_width = depth_params.res_scale_width = + (float)layout.top_screen.GetWidth() / VideoCore::kScreenTopWidth; + color_params.res_scale_height = depth_params.res_scale_height = + (float)layout.top_screen.GetHeight() / VideoCore::kScreenTopHeight; } color_params.addr = config.GetColorBufferPhysicalAddress(); @@ -523,22 +584,28 @@ std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> RasterizerC depth_params.pixel_format = CachedSurface::PixelFormatFromDepthFormat(config.depth_format); MathUtil::Rectangle<int> color_rect; - CachedSurface* color_surface = using_color_fb ? GetSurfaceRect(color_params, true, true, color_rect) : nullptr; + CachedSurface* color_surface = + using_color_fb ? GetSurfaceRect(color_params, true, true, color_rect) : nullptr; MathUtil::Rectangle<int> depth_rect; - CachedSurface* depth_surface = using_depth_fb ? GetSurfaceRect(depth_params, true, true, depth_rect) : nullptr; + CachedSurface* depth_surface = + using_depth_fb ? GetSurfaceRect(depth_params, true, true, depth_rect) : nullptr; // Sanity check to make sure found surfaces aren't the same if (using_depth_fb && using_color_fb && color_surface == depth_surface) { - LOG_CRITICAL(Render_OpenGL, "Color and depth framebuffer surfaces overlap; overlapping surfaces not supported!"); + LOG_CRITICAL( + Render_OpenGL, + "Color and depth framebuffer surfaces overlap; overlapping surfaces not supported!"); using_depth_fb = false; depth_surface = nullptr; } MathUtil::Rectangle<int> rect; - if (color_surface != nullptr && depth_surface != nullptr && (depth_rect.left != color_rect.left || depth_rect.top != color_rect.top)) { - // Can't specify separate color and depth viewport offsets in OpenGL, so re-zero both if they don't match + if (color_surface != nullptr && depth_surface != nullptr && + (depth_rect.left != color_rect.left || depth_rect.top != color_rect.top)) { + // Can't specify separate color and depth viewport offsets in OpenGL, so re-zero both if + // they don't match if (color_rect.left != 0 || color_rect.top != 0) { color_surface = GetSurface(color_params, true, true); } @@ -548,9 +615,13 @@ std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> RasterizerC } if (!color_surface->is_tiled) { - rect = MathUtil::Rectangle<int>(0, 0, (int)(color_params.width * color_params.res_scale_width), (int)(color_params.height * color_params.res_scale_height)); + rect = MathUtil::Rectangle<int>( + 0, 0, (int)(color_params.width * color_params.res_scale_width), + (int)(color_params.height * color_params.res_scale_height)); } else { - rect = MathUtil::Rectangle<int>(0, (int)(color_params.height * color_params.res_scale_height), (int)(color_params.width * color_params.res_scale_width), 0); + rect = MathUtil::Rectangle<int>( + 0, (int)(color_params.height * color_params.res_scale_height), + (int)(color_params.width * color_params.res_scale_width), 0); } } else if (color_surface != nullptr) { rect = color_rect; @@ -564,7 +635,8 @@ std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> RasterizerC } CachedSurface* RasterizerCacheOpenGL::TryGetFillSurface(const GPU::Regs::MemoryFillConfig& config) { - auto surface_interval = boost::icl::interval<PAddr>::right_open(config.GetStartAddress(), config.GetEndAddress()); + auto surface_interval = + boost::icl::interval<PAddr>::right_open(config.GetStartAddress(), config.GetEndAddress()); auto range = surface_cache.equal_range(surface_interval); for (auto it = range.first; it != range.second; ++it) { for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2) { @@ -581,8 +653,9 @@ CachedSurface* RasterizerCacheOpenGL::TryGetFillSurface(const GPU::Regs::MemoryF if (surface->addr == config.GetStartAddress() && CachedSurface::GetFormatBpp(surface->pixel_format) == bits_per_value && - (surface->width * surface->height * CachedSurface::GetFormatBpp(surface->pixel_format) / 8) == (config.GetEndAddress() - config.GetStartAddress())) - { + (surface->width * surface->height * + CachedSurface::GetFormatBpp(surface->pixel_format) / 8) == + (config.GetEndAddress() - config.GetStartAddress())) { return surface; } } @@ -617,8 +690,11 @@ void RasterizerCacheOpenGL::FlushSurface(CachedSurface* surface) { if (surface->res_scale_width != 1.f || surface->res_scale_height != 1.f) { unscaled_tex.Create(); - AllocateSurfaceTexture(unscaled_tex.handle, surface->pixel_format, surface->width, surface->height); - BlitTextures(surface->texture.handle, unscaled_tex.handle, CachedSurface::GetFormatType(surface->pixel_format), + AllocateSurfaceTexture(unscaled_tex.handle, surface->pixel_format, surface->width, + surface->height); + BlitTextures( + surface->texture.handle, unscaled_tex.handle, + CachedSurface::GetFormatType(surface->pixel_format), MathUtil::Rectangle<int>(0, 0, surface->GetScaledWidth(), surface->GetScaledHeight()), MathUtil::Rectangle<int>(0, 0, surface->width, surface->height)); @@ -648,10 +724,14 @@ void RasterizerCacheOpenGL::FlushSurface(CachedSurface* surface) { glGetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type, temp_gl_buffer.data()); - // Directly copy pixels. Internal OpenGL color formats are consistent so no conversion is necessary. - MortonCopyPixels(surface->pixel_format, surface->width, surface->height, bytes_per_pixel, bytes_per_pixel, dst_buffer, temp_gl_buffer.data(), false); + // Directly copy pixels. Internal OpenGL color formats are consistent so no conversion + // is necessary. + MortonCopyPixels(surface->pixel_format, surface->width, surface->height, + bytes_per_pixel, bytes_per_pixel, dst_buffer, temp_gl_buffer.data(), + false); } else { - // Depth/Stencil formats need special treatment since they aren't sampleable using LookupTexture and can't use RGBA format + // Depth/Stencil formats need special treatment since they aren't sampleable using + // LookupTexture and can't use RGBA format size_t tuple_idx = (size_t)surface->pixel_format - 14; ASSERT(tuple_idx < depth_format_tuples.size()); const FormatTuple& tuple = depth_format_tuples[tuple_idx]; @@ -669,7 +749,9 @@ void RasterizerCacheOpenGL::FlushSurface(CachedSurface* surface) { u8* temp_gl_buffer_ptr = use_4bpp ? temp_gl_buffer.data() + 1 : temp_gl_buffer.data(); - MortonCopyPixels(surface->pixel_format, surface->width, surface->height, bytes_per_pixel, gl_bytes_per_pixel, dst_buffer, temp_gl_buffer_ptr, false); + MortonCopyPixels(surface->pixel_format, surface->width, surface->height, + bytes_per_pixel, gl_bytes_per_pixel, dst_buffer, temp_gl_buffer_ptr, + false); } } glPixelStorei(GL_PACK_ROW_LENGTH, 0); @@ -680,7 +762,8 @@ void RasterizerCacheOpenGL::FlushSurface(CachedSurface* surface) { cur_state.Apply(); } -void RasterizerCacheOpenGL::FlushRegion(PAddr addr, u32 size, const CachedSurface* skip_surface, bool invalidate) { +void RasterizerCacheOpenGL::FlushRegion(PAddr addr, u32 size, const CachedSurface* skip_surface, + bool invalidate) { if (size == 0) { return; } @@ -691,8 +774,11 @@ void RasterizerCacheOpenGL::FlushRegion(PAddr addr, u32 size, const CachedSurfac auto surface_interval = boost::icl::interval<PAddr>::right_open(addr, addr + size); auto cache_upper_bound = surface_cache.upper_bound(surface_interval); for (auto it = surface_cache.lower_bound(surface_interval); it != cache_upper_bound; ++it) { - std::copy_if(it->second.begin(), it->second.end(), std::inserter(touching_surfaces, touching_surfaces.end()), - [skip_surface](std::shared_ptr<CachedSurface> surface) { return (surface.get() != skip_surface); }); + std::copy_if(it->second.begin(), it->second.end(), + std::inserter(touching_surfaces, touching_surfaces.end()), + [skip_surface](std::shared_ptr<CachedSurface> surface) { + return (surface.get() != skip_surface); + }); } // Flush and invalidate surfaces @@ -700,7 +786,10 @@ void RasterizerCacheOpenGL::FlushRegion(PAddr addr, u32 size, const CachedSurfac FlushSurface(surface.get()); if (invalidate) { Memory::RasterizerMarkRegionCached(surface->addr, surface->size, -1); - surface_cache.subtract(std::make_pair(boost::icl::interval<PAddr>::right_open(surface->addr, surface->addr + surface->size), std::set<std::shared_ptr<CachedSurface>>({ surface }))); + surface_cache.subtract( + std::make_pair(boost::icl::interval<PAddr>::right_open( + surface->addr, surface->addr + surface->size), + std::set<std::shared_ptr<CachedSurface>>({surface}))); } } } diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 225596415..db5b649da 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -22,7 +22,8 @@ #include "video_core/renderer_opengl/gl_resource_manager.h" namespace MathUtil { -template <class T> struct Rectangle; +template <class T> +struct Rectangle; } struct CachedSurface; @@ -32,38 +33,38 @@ using SurfaceCache = boost::icl::interval_map<PAddr, std::set<std::shared_ptr<Ca struct CachedSurface { enum class PixelFormat { // First 5 formats are shared between textures and color buffers - RGBA8 = 0, - RGB8 = 1, - RGB5A1 = 2, - RGB565 = 3, - RGBA4 = 4, + RGBA8 = 0, + RGB8 = 1, + RGB5A1 = 2, + RGB565 = 3, + RGBA4 = 4, // Texture-only formats - IA8 = 5, - RG8 = 6, - I8 = 7, - A8 = 8, - IA4 = 9, - I4 = 10, - A4 = 11, - ETC1 = 12, - ETC1A4 = 13, + IA8 = 5, + RG8 = 6, + I8 = 7, + A8 = 8, + IA4 = 9, + I4 = 10, + A4 = 11, + ETC1 = 12, + ETC1A4 = 13, // Depth buffer-only formats - D16 = 14, + D16 = 14, // gap - D24 = 16, - D24S8 = 17, + D24 = 16, + D24S8 = 17, - Invalid = 255, + Invalid = 255, }; enum class SurfaceType { - Color = 0, - Texture = 1, - Depth = 2, + Color = 0, + Texture = 1, + Depth = 2, DepthStencil = 3, - Invalid = 4, + Invalid = 4, }; static unsigned int GetFormatBpp(CachedSurface::PixelFormat format) { @@ -101,7 +102,8 @@ struct CachedSurface { } static PixelFormat PixelFormatFromDepthFormat(Pica::Regs::DepthFormat format) { - return ((unsigned int)format < 4) ? (PixelFormat)((unsigned int)format + 14) : PixelFormat::Invalid; + return ((unsigned int)format < 4) ? (PixelFormat)((unsigned int)format + 14) + : PixelFormat::Invalid; } static PixelFormat PixelFormatFromGPUPixelFormat(GPU::Regs::PixelFormat format) { @@ -120,7 +122,8 @@ struct CachedSurface { SurfaceType a_type = GetFormatType(pixel_format_a); SurfaceType b_type = GetFormatType(pixel_format_b); - if ((a_type == SurfaceType::Color || a_type == SurfaceType::Texture) && (b_type == SurfaceType::Color || b_type == SurfaceType::Texture)) { + if ((a_type == SurfaceType::Color || a_type == SurfaceType::Texture) && + (b_type == SurfaceType::Color || b_type == SurfaceType::Texture)) { return true; } @@ -187,22 +190,30 @@ public: ~RasterizerCacheOpenGL(); /// Blits one texture to another - bool BlitTextures(GLuint src_tex, GLuint dst_tex, CachedSurface::SurfaceType type, const MathUtil::Rectangle<int>& src_rect, const MathUtil::Rectangle<int>& dst_rect); + bool BlitTextures(GLuint src_tex, GLuint dst_tex, CachedSurface::SurfaceType type, + const MathUtil::Rectangle<int>& src_rect, + const MathUtil::Rectangle<int>& dst_rect); /// Attempt to blit one surface's texture to another - bool TryBlitSurfaces(CachedSurface* src_surface, const MathUtil::Rectangle<int>& src_rect, CachedSurface* dst_surface, const MathUtil::Rectangle<int>& dst_rect); + bool TryBlitSurfaces(CachedSurface* src_surface, const MathUtil::Rectangle<int>& src_rect, + CachedSurface* dst_surface, const MathUtil::Rectangle<int>& dst_rect); /// Loads a texture from 3DS memory to OpenGL and caches it (if not already cached) - CachedSurface* GetSurface(const CachedSurface& params, bool match_res_scale, bool load_if_create); + CachedSurface* GetSurface(const CachedSurface& params, bool match_res_scale, + bool load_if_create); - /// Attempt to find a subrect (resolution scaled) of a surface, otherwise loads a texture from 3DS memory to OpenGL and caches it (if not already cached) - CachedSurface* GetSurfaceRect(const CachedSurface& params, bool match_res_scale, bool load_if_create, MathUtil::Rectangle<int>& out_rect); + /// Attempt to find a subrect (resolution scaled) of a surface, otherwise loads a texture from + /// 3DS memory to OpenGL and caches it (if not already cached) + CachedSurface* GetSurfaceRect(const CachedSurface& params, bool match_res_scale, + bool load_if_create, MathUtil::Rectangle<int>& out_rect); /// Gets a surface based on the texture configuration CachedSurface* GetTextureSurface(const Pica::Regs::FullTextureConfig& config); - /// Gets the color and depth surfaces and rect (resolution scaled) based on the framebuffer configuration - std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> GetFramebufferSurfaces(const Pica::Regs::FramebufferConfig& config); + /// Gets the color and depth surfaces and rect (resolution scaled) based on the framebuffer + /// configuration + std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> + GetFramebufferSurfaces(const Pica::Regs::FramebufferConfig& config); /// Attempt to get a surface that exactly matches the fill region and format CachedSurface* TryGetFillSurface(const GPU::Regs::MemoryFillConfig& config); @@ -210,7 +221,8 @@ public: /// Write the surface back to memory void FlushSurface(CachedSurface* surface); - /// Write any cached resources overlapping the region back to memory (if dirty) and optionally invalidate them in the cache + /// Write any cached resources overlapping the region back to memory (if dirty) and optionally + /// invalidate them in the cache void FlushRegion(PAddr addr, u32 size, const CachedSurface* skip_surface, bool invalidate); /// Flush all cached resources tracked by this cache manager diff --git a/src/video_core/renderer_opengl/gl_resource_manager.h b/src/video_core/renderer_opengl/gl_resource_manager.h index eb128966c..2f40eb646 100644 --- a/src/video_core/renderer_opengl/gl_resource_manager.h +++ b/src/video_core/renderer_opengl/gl_resource_manager.h @@ -16,19 +16,28 @@ class OGLTexture : private NonCopyable { public: OGLTexture() = default; - OGLTexture(OGLTexture&& o) { std::swap(handle, o.handle); } - ~OGLTexture() { Release(); } - OGLTexture& operator=(OGLTexture&& o) { std::swap(handle, o.handle); return *this; } + OGLTexture(OGLTexture&& o) { + std::swap(handle, o.handle); + } + ~OGLTexture() { + Release(); + } + OGLTexture& operator=(OGLTexture&& o) { + std::swap(handle, o.handle); + return *this; + } /// Creates a new internal OpenGL resource and stores the handle void Create() { - if (handle != 0) return; + if (handle != 0) + return; glGenTextures(1, &handle); } /// Deletes the internal OpenGL resource void Release() { - if (handle == 0) return; + if (handle == 0) + return; glDeleteTextures(1, &handle); OpenGLState::ResetTexture(handle); handle = 0; @@ -40,19 +49,28 @@ public: class OGLSampler : private NonCopyable { public: OGLSampler() = default; - OGLSampler(OGLSampler&& o) { std::swap(handle, o.handle); } - ~OGLSampler() { Release(); } - OGLSampler& operator=(OGLSampler&& o) { std::swap(handle, o.handle); return *this; } + OGLSampler(OGLSampler&& o) { + std::swap(handle, o.handle); + } + ~OGLSampler() { + Release(); + } + OGLSampler& operator=(OGLSampler&& o) { + std::swap(handle, o.handle); + return *this; + } /// Creates a new internal OpenGL resource and stores the handle void Create() { - if (handle != 0) return; + if (handle != 0) + return; glGenSamplers(1, &handle); } /// Deletes the internal OpenGL resource void Release() { - if (handle == 0) return; + if (handle == 0) + return; glDeleteSamplers(1, &handle); OpenGLState::ResetSampler(handle); handle = 0; @@ -64,19 +82,28 @@ public: class OGLShader : private NonCopyable { public: OGLShader() = default; - OGLShader(OGLShader&& o) { std::swap(handle, o.handle); } - ~OGLShader() { Release(); } - OGLShader& operator=(OGLShader&& o) { std::swap(handle, o.handle); return *this; } + OGLShader(OGLShader&& o) { + std::swap(handle, o.handle); + } + ~OGLShader() { + Release(); + } + OGLShader& operator=(OGLShader&& o) { + std::swap(handle, o.handle); + return *this; + } /// Creates a new internal OpenGL resource and stores the handle void Create(const char* vert_shader, const char* frag_shader) { - if (handle != 0) return; + if (handle != 0) + return; handle = GLShader::LoadProgram(vert_shader, frag_shader); } /// Deletes the internal OpenGL resource void Release() { - if (handle == 0) return; + if (handle == 0) + return; glDeleteProgram(handle); OpenGLState::ResetProgram(handle); handle = 0; @@ -88,19 +115,28 @@ public: class OGLBuffer : private NonCopyable { public: OGLBuffer() = default; - OGLBuffer(OGLBuffer&& o) { std::swap(handle, o.handle); } - ~OGLBuffer() { Release(); } - OGLBuffer& operator=(OGLBuffer&& o) { std::swap(handle, o.handle); return *this; } + OGLBuffer(OGLBuffer&& o) { + std::swap(handle, o.handle); + } + ~OGLBuffer() { + Release(); + } + OGLBuffer& operator=(OGLBuffer&& o) { + std::swap(handle, o.handle); + return *this; + } /// Creates a new internal OpenGL resource and stores the handle void Create() { - if (handle != 0) return; + if (handle != 0) + return; glGenBuffers(1, &handle); } /// Deletes the internal OpenGL resource void Release() { - if (handle == 0) return; + if (handle == 0) + return; glDeleteBuffers(1, &handle); OpenGLState::ResetBuffer(handle); handle = 0; @@ -112,19 +148,28 @@ public: class OGLVertexArray : private NonCopyable { public: OGLVertexArray() = default; - OGLVertexArray(OGLVertexArray&& o) { std::swap(handle, o.handle); } - ~OGLVertexArray() { Release(); } - OGLVertexArray& operator=(OGLVertexArray&& o) { std::swap(handle, o.handle); return *this; } + OGLVertexArray(OGLVertexArray&& o) { + std::swap(handle, o.handle); + } + ~OGLVertexArray() { + Release(); + } + OGLVertexArray& operator=(OGLVertexArray&& o) { + std::swap(handle, o.handle); + return *this; + } /// Creates a new internal OpenGL resource and stores the handle void Create() { - if (handle != 0) return; + if (handle != 0) + return; glGenVertexArrays(1, &handle); } /// Deletes the internal OpenGL resource void Release() { - if (handle == 0) return; + if (handle == 0) + return; glDeleteVertexArrays(1, &handle); OpenGLState::ResetVertexArray(handle); handle = 0; @@ -136,19 +181,28 @@ public: class OGLFramebuffer : private NonCopyable { public: OGLFramebuffer() = default; - OGLFramebuffer(OGLFramebuffer&& o) { std::swap(handle, o.handle); } - ~OGLFramebuffer() { Release(); } - OGLFramebuffer& operator=(OGLFramebuffer&& o) { std::swap(handle, o.handle); return *this; } + OGLFramebuffer(OGLFramebuffer&& o) { + std::swap(handle, o.handle); + } + ~OGLFramebuffer() { + Release(); + } + OGLFramebuffer& operator=(OGLFramebuffer&& o) { + std::swap(handle, o.handle); + return *this; + } /// Creates a new internal OpenGL resource and stores the handle void Create() { - if (handle != 0) return; + if (handle != 0) + return; glGenFramebuffers(1, &handle); } /// Deletes the internal OpenGL resource void Release() { - if (handle == 0) return; + if (handle == 0) + return; glDeleteFramebuffers(1, &handle); OpenGLState::ResetFramebuffer(handle); handle = 0; diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 3de372f67..f86cffee5 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -21,19 +21,18 @@ namespace GLShader { /// Detects if a TEV stage is configured to be skipped (to avoid generating unnecessary code) static bool IsPassThroughTevStage(const TevStageConfig& stage) { - return (stage.color_op == TevStageConfig::Operation::Replace && - stage.alpha_op == TevStageConfig::Operation::Replace && - stage.color_source1 == TevStageConfig::Source::Previous && - stage.alpha_source1 == TevStageConfig::Source::Previous && - stage.color_modifier1 == TevStageConfig::ColorModifier::SourceColor && - stage.alpha_modifier1 == TevStageConfig::AlphaModifier::SourceAlpha && - stage.GetColorMultiplier() == 1 && - stage.GetAlphaMultiplier() == 1); + return (stage.color_op == TevStageConfig::Operation::Replace && + stage.alpha_op == TevStageConfig::Operation::Replace && + stage.color_source1 == TevStageConfig::Source::Previous && + stage.alpha_source1 == TevStageConfig::Source::Previous && + stage.color_modifier1 == TevStageConfig::ColorModifier::SourceColor && + stage.alpha_modifier1 == TevStageConfig::AlphaModifier::SourceAlpha && + stage.GetColorMultiplier() == 1 && stage.GetAlphaMultiplier() == 1); } /// Writes the specified TEV stage source component(s) -static void AppendSource(std::string& out, const PicaShaderConfig& config, TevStageConfig::Source source, - const std::string& index_name) { +static void AppendSource(std::string& out, const PicaShaderConfig& config, + TevStageConfig::Source source, const std::string& index_name) { const auto& state = config.state; using Source = TevStageConfig::Source; switch (source) { @@ -48,7 +47,7 @@ static void AppendSource(std::string& out, const PicaShaderConfig& config, TevSt break; case Source::Texture0: // Only unit 0 respects the texturing type (according to 3DBrew) - switch(state.texture0_type) { + switch (state.texture0_type) { case Pica::Regs::TextureConfig::Texture2D: out += "texture(tex[0], texcoord[0])"; break; @@ -57,7 +56,8 @@ static void AppendSource(std::string& out, const PicaShaderConfig& config, TevSt break; default: out += "texture(tex[0], texcoord[0])"; - LOG_CRITICAL(HW_GPU, "Unhandled texture type %x", static_cast<int>(state.texture0_type)); + LOG_CRITICAL(HW_GPU, "Unhandled texture type %x", + static_cast<int>(state.texture0_type)); UNIMPLEMENTED(); break; } @@ -85,8 +85,9 @@ static void AppendSource(std::string& out, const PicaShaderConfig& config, TevSt } /// Writes the color components to use for the specified TEV stage color modifier -static void AppendColorModifier(std::string& out, const PicaShaderConfig& config, TevStageConfig::ColorModifier modifier, - TevStageConfig::Source source, const std::string& index_name) { +static void AppendColorModifier(std::string& out, const PicaShaderConfig& config, + TevStageConfig::ColorModifier modifier, + TevStageConfig::Source source, const std::string& index_name) { using ColorModifier = TevStageConfig::ColorModifier; switch (modifier) { case ColorModifier::SourceColor: @@ -142,8 +143,9 @@ static void AppendColorModifier(std::string& out, const PicaShaderConfig& config } /// Writes the alpha component to use for the specified TEV stage alpha modifier -static void AppendAlphaModifier(std::string& out, const PicaShaderConfig& config, TevStageConfig::AlphaModifier modifier, - TevStageConfig::Source source, const std::string& index_name) { +static void AppendAlphaModifier(std::string& out, const PicaShaderConfig& config, + TevStageConfig::AlphaModifier modifier, + TevStageConfig::Source source, const std::string& index_name) { using AlphaModifier = TevStageConfig::AlphaModifier; switch (modifier) { case AlphaModifier::SourceAlpha: @@ -191,7 +193,7 @@ static void AppendAlphaModifier(std::string& out, const PicaShaderConfig& config /// Writes the combiner function for the color components for the specified TEV stage operation static void AppendColorCombiner(std::string& out, TevStageConfig::Operation operation, - const std::string& variable_name) { + const std::string& variable_name) { out += "clamp("; using Operation = TevStageConfig::Operation; switch (operation) { @@ -208,8 +210,10 @@ static void AppendColorCombiner(std::string& out, TevStageConfig::Operation oper out += variable_name + "[0] + " + variable_name + "[1] - vec3(0.5)"; break; case Operation::Lerp: - // TODO(bunnei): Verify if HW actually does this per-component, otherwise we can just use builtin lerp - out += variable_name + "[0] * " + variable_name + "[2] + " + variable_name + "[1] * (vec3(1.0) - " + variable_name + "[2])"; + // TODO(bunnei): Verify if HW actually does this per-component, otherwise we can just use + // builtin lerp + out += variable_name + "[0] * " + variable_name + "[2] + " + variable_name + + "[1] * (vec3(1.0) - " + variable_name + "[2])"; break; case Operation::Subtract: out += variable_name + "[0] - " + variable_name + "[1]"; @@ -218,10 +222,12 @@ static void AppendColorCombiner(std::string& out, TevStageConfig::Operation oper out += variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2]"; break; case Operation::AddThenMultiply: - out += "min(" + variable_name + "[0] + " + variable_name + "[1], vec3(1.0)) * " + variable_name + "[2]"; + out += "min(" + variable_name + "[0] + " + variable_name + "[1], vec3(1.0)) * " + + variable_name + "[2]"; break; case Operation::Dot3_RGB: - out += "vec3(dot(" + variable_name + "[0] - vec3(0.5), " + variable_name + "[1] - vec3(0.5)) * 4.0)"; + out += "vec3(dot(" + variable_name + "[0] - vec3(0.5), " + variable_name + + "[1] - vec3(0.5)) * 4.0)"; break; default: out += "vec3(0.0)"; @@ -233,7 +239,7 @@ static void AppendColorCombiner(std::string& out, TevStageConfig::Operation oper /// Writes the combiner function for the alpha component for the specified TEV stage operation static void AppendAlphaCombiner(std::string& out, TevStageConfig::Operation operation, - const std::string& variable_name) { + const std::string& variable_name) { out += "clamp("; using Operation = TevStageConfig::Operation; switch (operation) { @@ -250,7 +256,8 @@ static void AppendAlphaCombiner(std::string& out, TevStageConfig::Operation oper out += variable_name + "[0] + " + variable_name + "[1] - 0.5"; break; case Operation::Lerp: - out += variable_name + "[0] * " + variable_name + "[2] + " + variable_name + "[1] * (1.0 - " + variable_name + "[2])"; + out += variable_name + "[0] * " + variable_name + "[2] + " + variable_name + + "[1] * (1.0 - " + variable_name + "[2])"; break; case Operation::Subtract: out += variable_name + "[0] - " + variable_name + "[1]"; @@ -259,7 +266,8 @@ static void AppendAlphaCombiner(std::string& out, TevStageConfig::Operation oper out += variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2]"; break; case Operation::AddThenMultiply: - out += "min(" + variable_name + "[0] + " + variable_name + "[1], 1.0) * " + variable_name + "[2]"; + out += "min(" + variable_name + "[0] + " + variable_name + "[1], 1.0) * " + variable_name + + "[2]"; break; default: out += "0.0"; @@ -284,9 +292,10 @@ static void AppendAlphaTestCondition(std::string& out, Regs::CompareFunc func) { case CompareFunc::LessThan: case CompareFunc::LessThanOrEqual: case CompareFunc::GreaterThan: - case CompareFunc::GreaterThanOrEqual: - { - static const char* op[] = { "!=", "==", ">=", ">", "<=", "<", }; + case CompareFunc::GreaterThanOrEqual: { + static const char* op[] = { + "!=", "==", ">=", ">", "<=", "<", + }; unsigned index = (unsigned)func - (unsigned)CompareFunc::Equal; out += "int(last_tex_env_out.a * 255.0f) " + std::string(op[index]) + " alphatest_ref"; break; @@ -301,7 +310,8 @@ static void AppendAlphaTestCondition(std::string& out, Regs::CompareFunc func) { /// Writes the code to emulate the specified TEV stage static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsigned index) { - const auto stage = static_cast<const Pica::Regs::TevStageConfig>(config.state.tev_stages[index]); + const auto stage = + static_cast<const Pica::Regs::TevStageConfig>(config.state.tev_stages[index]); if (!IsPassThroughTevStage(stage)) { std::string index_name = std::to_string(index); @@ -330,8 +340,12 @@ static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsi out += ";\n"; out += "last_tex_env_out = vec4(" - "clamp(color_output_" + index_name + " * " + std::to_string(stage.GetColorMultiplier()) + ".0, vec3(0.0), vec3(1.0))," - "clamp(alpha_output_" + index_name + " * " + std::to_string(stage.GetAlphaMultiplier()) + ".0, 0.0, 1.0));\n"; + "clamp(color_output_" + + index_name + " * " + std::to_string(stage.GetColorMultiplier()) + + ".0, vec3(0.0), vec3(1.0))," + "clamp(alpha_output_" + + index_name + " * " + std::to_string(stage.GetAlphaMultiplier()) + + ".0, 0.0, 1.0));\n"; } out += "combiner_buffer = next_combiner_buffer;\n"; @@ -355,13 +369,17 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { // Compute fragment normals if (lighting.bump_mode == Pica::Regs::LightingBumpMode::NormalMap) { - // Bump mapping is enabled using a normal map, read perturbation vector from the selected texture + // Bump mapping is enabled using a normal map, read perturbation vector from the selected + // texture std::string bump_selector = std::to_string(lighting.bump_selector); - out += "vec3 surface_normal = 2.0 * texture(tex[" + bump_selector + "], texcoord[" + bump_selector + "]).rgb - 1.0;\n"; + out += "vec3 surface_normal = 2.0 * texture(tex[" + bump_selector + "], texcoord[" + + bump_selector + "]).rgb - 1.0;\n"; - // Recompute Z-component of perturbation if 'renorm' is enabled, this provides a higher precision result + // Recompute Z-component of perturbation if 'renorm' is enabled, this provides a higher + // precision result if (lighting.bump_renorm) { - std::string val = "(1.0 - (surface_normal.x*surface_normal.x + surface_normal.y*surface_normal.y))"; + std::string val = + "(1.0 - (surface_normal.x*surface_normal.x + surface_normal.y*surface_normal.y))"; out += "surface_normal.z = sqrt(max(" + val + ", 0.0));\n"; } } else if (lighting.bump_mode == Pica::Regs::LightingBumpMode::TangentMap) { @@ -373,7 +391,8 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { out += "vec3 surface_normal = vec3(0.0, 0.0, 1.0);\n"; } - // Rotate the surface-local normal by the interpolated normal quaternion to convert it to eyespace + // Rotate the surface-local normal by the interpolated normal quaternion to convert it to + // eyespace out += "vec3 normal = normalize(quaternion_rotate(normquat, surface_normal));\n"; // Gets the index into the specified lookup table for specular lighting @@ -406,12 +425,14 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { if (abs) { // LUT index is in the range of (0.0, 1.0) - index = lighting.light[light_num].two_sided_diffuse ? "abs(" + index + ")" : "max(" + index + ", 0.f)"; + index = lighting.light[light_num].two_sided_diffuse ? "abs(" + index + ")" + : "max(" + index + ", 0.f)"; return "(FLOAT_255 * clamp(" + index + ", 0.0, 1.0))"; } else { // LUT index is in the range of (-1.0, 1.0) index = "clamp(" + index + ", -1.0, 1.0)"; - return "(FLOAT_255 * ((" + index + " < 0) ? " + index + " + 2.0 : " + index + ") / 2.0)"; + return "(FLOAT_255 * ((" + index + " < 0) ? " + index + " + 2.0 : " + index + + ") / 2.0)"; } return std::string(); @@ -434,52 +455,74 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { else out += "light_vector = normalize(" + light_src + ".position + view);\n"; - // Compute dot product of light_vector and normal, adjust if lighting is one-sided or two-sided - std::string dot_product = light_config.two_sided_diffuse ? "abs(dot(light_vector, normal))" : "max(dot(light_vector, normal), 0.0)"; + // Compute dot product of light_vector and normal, adjust if lighting is one-sided or + // two-sided + std::string dot_product = light_config.two_sided_diffuse + ? "abs(dot(light_vector, normal))" + : "max(dot(light_vector, normal), 0.0)"; // If enabled, compute distance attenuation value std::string dist_atten = "1.0"; if (light_config.dist_atten_enable) { - std::string index = "(" + light_src + ".dist_atten_scale * length(-view - " + light_src + ".position) + " + light_src + ".dist_atten_bias)"; + std::string index = "(" + light_src + ".dist_atten_scale * length(-view - " + + light_src + ".position) + " + light_src + ".dist_atten_bias)"; index = "((clamp(" + index + ", 0.0, FLOAT_255)))"; - const unsigned lut_num = ((unsigned)Regs::LightingSampler::DistanceAttenuation + light_config.num); + const unsigned lut_num = + ((unsigned)Regs::LightingSampler::DistanceAttenuation + light_config.num); dist_atten = GetLutValue((Regs::LightingSampler)lut_num, index); } // If enabled, clamp specular component if lighting result is negative - std::string clamp_highlights = lighting.clamp_highlights ? "(dot(light_vector, normal) <= 0.0 ? 0.0 : 1.0)" : "1.0"; + std::string clamp_highlights = + lighting.clamp_highlights ? "(dot(light_vector, normal) <= 0.0 ? 0.0 : 1.0)" : "1.0"; // Specular 0 component std::string d0_lut_value = "1.0"; - if (lighting.lut_d0.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::Distribution0)) { + if (lighting.lut_d0.enable && + Pica::Regs::IsLightingSamplerSupported(lighting.config, + Pica::Regs::LightingSampler::Distribution0)) { // Lookup specular "distribution 0" LUT value - std::string index = GetLutIndex(light_config.num, lighting.lut_d0.type, lighting.lut_d0.abs_input); - d0_lut_value = "(" + std::to_string(lighting.lut_d0.scale) + " * " + GetLutValue(Regs::LightingSampler::Distribution0, index) + ")"; + std::string index = + GetLutIndex(light_config.num, lighting.lut_d0.type, lighting.lut_d0.abs_input); + d0_lut_value = "(" + std::to_string(lighting.lut_d0.scale) + " * " + + GetLutValue(Regs::LightingSampler::Distribution0, index) + ")"; } std::string specular_0 = "(" + d0_lut_value + " * " + light_src + ".specular_0)"; // If enabled, lookup ReflectRed value, otherwise, 1.0 is used - if (lighting.lut_rr.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::ReflectRed)) { - std::string index = GetLutIndex(light_config.num, lighting.lut_rr.type, lighting.lut_rr.abs_input); - std::string value = "(" + std::to_string(lighting.lut_rr.scale) + " * " + GetLutValue(Regs::LightingSampler::ReflectRed, index) + ")"; + if (lighting.lut_rr.enable && + Pica::Regs::IsLightingSamplerSupported(lighting.config, + Pica::Regs::LightingSampler::ReflectRed)) { + std::string index = + GetLutIndex(light_config.num, lighting.lut_rr.type, lighting.lut_rr.abs_input); + std::string value = "(" + std::to_string(lighting.lut_rr.scale) + " * " + + GetLutValue(Regs::LightingSampler::ReflectRed, index) + ")"; out += "refl_value.r = " + value + ";\n"; } else { out += "refl_value.r = 1.0;\n"; } // If enabled, lookup ReflectGreen value, otherwise, ReflectRed value is used - if (lighting.lut_rg.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::ReflectGreen)) { - std::string index = GetLutIndex(light_config.num, lighting.lut_rg.type, lighting.lut_rg.abs_input); - std::string value = "(" + std::to_string(lighting.lut_rg.scale) + " * " + GetLutValue(Regs::LightingSampler::ReflectGreen, index) + ")"; + if (lighting.lut_rg.enable && + Pica::Regs::IsLightingSamplerSupported(lighting.config, + Pica::Regs::LightingSampler::ReflectGreen)) { + std::string index = + GetLutIndex(light_config.num, lighting.lut_rg.type, lighting.lut_rg.abs_input); + std::string value = "(" + std::to_string(lighting.lut_rg.scale) + " * " + + GetLutValue(Regs::LightingSampler::ReflectGreen, index) + ")"; out += "refl_value.g = " + value + ";\n"; } else { out += "refl_value.g = refl_value.r;\n"; } // If enabled, lookup ReflectBlue value, otherwise, ReflectRed value is used - if (lighting.lut_rb.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::ReflectBlue)) { - std::string index = GetLutIndex(light_config.num, lighting.lut_rb.type, lighting.lut_rb.abs_input); - std::string value = "(" + std::to_string(lighting.lut_rb.scale) + " * " + GetLutValue(Regs::LightingSampler::ReflectBlue, index) + ")"; + if (lighting.lut_rb.enable && + Pica::Regs::IsLightingSamplerSupported(lighting.config, + Pica::Regs::LightingSampler::ReflectBlue)) { + std::string index = + GetLutIndex(light_config.num, lighting.lut_rb.type, lighting.lut_rb.abs_input); + std::string value = "(" + std::to_string(lighting.lut_rb.scale) + " * " + + GetLutValue(Regs::LightingSampler::ReflectBlue, index) + ")"; out += "refl_value.b = " + value + ";\n"; } else { out += "refl_value.b = refl_value.r;\n"; @@ -487,18 +530,26 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { // Specular 1 component std::string d1_lut_value = "1.0"; - if (lighting.lut_d1.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::Distribution1)) { + if (lighting.lut_d1.enable && + Pica::Regs::IsLightingSamplerSupported(lighting.config, + Pica::Regs::LightingSampler::Distribution1)) { // Lookup specular "distribution 1" LUT value - std::string index = GetLutIndex(light_config.num, lighting.lut_d1.type, lighting.lut_d1.abs_input); - d1_lut_value = "(" + std::to_string(lighting.lut_d1.scale) + " * " + GetLutValue(Regs::LightingSampler::Distribution1, index) + ")"; + std::string index = + GetLutIndex(light_config.num, lighting.lut_d1.type, lighting.lut_d1.abs_input); + d1_lut_value = "(" + std::to_string(lighting.lut_d1.scale) + " * " + + GetLutValue(Regs::LightingSampler::Distribution1, index) + ")"; } - std::string specular_1 = "(" + d1_lut_value + " * refl_value * " + light_src + ".specular_1)"; + std::string specular_1 = + "(" + d1_lut_value + " * refl_value * " + light_src + ".specular_1)"; // Fresnel - if (lighting.lut_fr.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::Fresnel)) { + if (lighting.lut_fr.enable && Pica::Regs::IsLightingSamplerSupported( + lighting.config, Pica::Regs::LightingSampler::Fresnel)) { // Lookup fresnel LUT value - std::string index = GetLutIndex(light_config.num, lighting.lut_fr.type, lighting.lut_fr.abs_input); - std::string value = "(" + std::to_string(lighting.lut_fr.scale) + " * " + GetLutValue(Regs::LightingSampler::Fresnel, index) + ")"; + std::string index = + GetLutIndex(light_config.num, lighting.lut_fr.type, lighting.lut_fr.abs_input); + std::string value = "(" + std::to_string(lighting.lut_fr.scale) + " * " + + GetLutValue(Regs::LightingSampler::Fresnel, index) + ")"; // Enabled for difffuse lighting alpha component if (lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::PrimaryAlpha || @@ -512,10 +563,12 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { } // Compute primary fragment color (diffuse lighting) function - out += "diffuse_sum.rgb += ((" + light_src + ".diffuse * " + dot_product + ") + " + light_src + ".ambient) * " + dist_atten + ";\n"; + out += "diffuse_sum.rgb += ((" + light_src + ".diffuse * " + dot_product + ") + " + + light_src + ".ambient) * " + dist_atten + ";\n"; // Compute secondary fragment color (specular lighting) function - out += "specular_sum.rgb += (" + specular_0 + " + " + specular_1 + ") * " + clamp_highlights + " * " + dist_atten + ";\n"; + out += "specular_sum.rgb += (" + specular_0 + " + " + specular_1 + ") * " + + clamp_highlights + " * " + dist_atten + ";\n"; } // Sum final lighting result @@ -598,9 +651,9 @@ vec4 secondary_fragment_color = vec4(0.0); out += "!"; // x2,y2 have +1 added to cover the entire pixel area out += "(gl_FragCoord.x >= scissor_x1 * framebuffer_scale.x && " - "gl_FragCoord.y >= scissor_y1 * framebuffer_scale.y && " - "gl_FragCoord.x < (scissor_x2 + 1) * framebuffer_scale.x && " - "gl_FragCoord.y < (scissor_y2 + 1) * framebuffer_scale.y)) discard;\n"; + "gl_FragCoord.y >= scissor_y1 * framebuffer_scale.y && " + "gl_FragCoord.x < (scissor_x2 + 1) * framebuffer_scale.x && " + "gl_FragCoord.y < (scissor_y2 + 1) * framebuffer_scale.y)) discard;\n"; } out += "float z_over_w = 1.0 - gl_FragCoord.z * 2.0;\n"; @@ -638,9 +691,11 @@ vec4 secondary_fragment_color = vec4(0.0); out += "float fog_i = clamp(floor(fog_index), 0.0, 127.0);\n"; out += "float fog_f = fog_index - fog_i;\n"; out += "uint fog_lut_entry = texelFetch(fog_lut, int(fog_i), 0).r;\n"; - out += "float fog_lut_entry_difference = float(int((fog_lut_entry & 0x1FFFU) << 19U) >> 19);\n"; // Extract signed difference + out += "float fog_lut_entry_difference = float(int((fog_lut_entry & 0x1FFFU) << 19U) >> " + "19);\n"; // Extract signed difference out += "float fog_lut_entry_value = float((fog_lut_entry >> 13U) & 0x7FFU);\n"; - out += "float fog_factor = (fog_lut_entry_value + fog_lut_entry_difference * fog_f) / 2047.0;\n"; + out += "float fog_factor = (fog_lut_entry_value + fog_lut_entry_difference * fog_f) / " + "2047.0;\n"; out += "fog_factor = clamp(fog_factor, 0.0, 1.0);\n"; // Blend the fog @@ -658,14 +713,20 @@ vec4 secondary_fragment_color = vec4(0.0); std::string GenerateVertexShader() { std::string out = "#version 330 core\n"; - out += "layout(location = " + std::to_string((int)ATTRIBUTE_POSITION) + ") in vec4 vert_position;\n"; - out += "layout(location = " + std::to_string((int)ATTRIBUTE_COLOR) + ") in vec4 vert_color;\n"; - out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD0) + ") in vec2 vert_texcoord0;\n"; - out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD1) + ") in vec2 vert_texcoord1;\n"; - out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD2) + ") in vec2 vert_texcoord2;\n"; - out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD0_W) + ") in float vert_texcoord0_w;\n"; - out += "layout(location = " + std::to_string((int)ATTRIBUTE_NORMQUAT) + ") in vec4 vert_normquat;\n"; - out += "layout(location = " + std::to_string((int)ATTRIBUTE_VIEW) + ") in vec3 vert_view;\n"; + out += "layout(location = " + std::to_string((int)ATTRIBUTE_POSITION) + + ") in vec4 vert_position;\n"; + out += "layout(location = " + std::to_string((int)ATTRIBUTE_COLOR) + ") in vec4 vert_color;\n"; + out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD0) + + ") in vec2 vert_texcoord0;\n"; + out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD1) + + ") in vec2 vert_texcoord1;\n"; + out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD2) + + ") in vec2 vert_texcoord2;\n"; + out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD0_W) + + ") in float vert_texcoord0_w;\n"; + out += "layout(location = " + std::to_string((int)ATTRIBUTE_NORMQUAT) + + ") in vec4 vert_normquat;\n"; + out += "layout(location = " + std::to_string((int)ATTRIBUTE_VIEW) + ") in vec3 vert_view;\n"; out += R"( out vec4 primary_color; diff --git a/src/video_core/renderer_opengl/gl_shader_util.cpp b/src/video_core/renderer_opengl/gl_shader_util.cpp index dded3db46..7d90ec6a3 100644 --- a/src/video_core/renderer_opengl/gl_shader_util.cpp +++ b/src/video_core/renderer_opengl/gl_shader_util.cpp @@ -56,7 +56,8 @@ GLuint LoadProgram(const char* vertex_shader, const char* fragment_shader) { if (result) { LOG_DEBUG(Render_OpenGL, "%s", &fragment_shader_error[0]); } else { - LOG_ERROR(Render_OpenGL, "Error compiling fragment shader:\n%s", &fragment_shader_error[0]); + LOG_ERROR(Render_OpenGL, "Error compiling fragment shader:\n%s", + &fragment_shader_error[0]); } } diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index 13ee986b9..a97269d44 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp @@ -106,11 +106,11 @@ void OpenGLState::Apply() const { // Color mask if (color_mask.red_enabled != cur_state.color_mask.red_enabled || - color_mask.green_enabled != cur_state.color_mask.green_enabled || - color_mask.blue_enabled != cur_state.color_mask.blue_enabled || - color_mask.alpha_enabled != cur_state.color_mask.alpha_enabled) { - glColorMask(color_mask.red_enabled, color_mask.green_enabled, - color_mask.blue_enabled, color_mask.alpha_enabled); + color_mask.green_enabled != cur_state.color_mask.green_enabled || + color_mask.blue_enabled != cur_state.color_mask.blue_enabled || + color_mask.alpha_enabled != cur_state.color_mask.alpha_enabled) { + glColorMask(color_mask.red_enabled, color_mask.green_enabled, color_mask.blue_enabled, + color_mask.alpha_enabled); } // Stencil test @@ -123,15 +123,16 @@ void OpenGLState::Apply() const { } if (stencil.test_func != cur_state.stencil.test_func || - stencil.test_ref != cur_state.stencil.test_ref || - stencil.test_mask != cur_state.stencil.test_mask) { + stencil.test_ref != cur_state.stencil.test_ref || + stencil.test_mask != cur_state.stencil.test_mask) { glStencilFunc(stencil.test_func, stencil.test_ref, stencil.test_mask); } if (stencil.action_depth_fail != cur_state.stencil.action_depth_fail || - stencil.action_depth_pass != cur_state.stencil.action_depth_pass || - stencil.action_stencil_fail != cur_state.stencil.action_stencil_fail) { - glStencilOp(stencil.action_stencil_fail, stencil.action_depth_fail, stencil.action_depth_pass); + stencil.action_depth_pass != cur_state.stencil.action_depth_pass || + stencil.action_stencil_fail != cur_state.stencil.action_stencil_fail) { + glStencilOp(stencil.action_stencil_fail, stencil.action_depth_fail, + stencil.action_depth_pass); } // Stencil mask @@ -154,23 +155,22 @@ void OpenGLState::Apply() const { } if (blend.color.red != cur_state.blend.color.red || - blend.color.green != cur_state.blend.color.green || - blend.color.blue != cur_state.blend.color.blue || - blend.color.alpha != cur_state.blend.color.alpha) { - glBlendColor(blend.color.red, blend.color.green, - blend.color.blue, blend.color.alpha); + blend.color.green != cur_state.blend.color.green || + blend.color.blue != cur_state.blend.color.blue || + blend.color.alpha != cur_state.blend.color.alpha) { + glBlendColor(blend.color.red, blend.color.green, blend.color.blue, blend.color.alpha); } if (blend.src_rgb_func != cur_state.blend.src_rgb_func || - blend.dst_rgb_func != cur_state.blend.dst_rgb_func || - blend.src_a_func != cur_state.blend.src_a_func || - blend.dst_a_func != cur_state.blend.dst_a_func) { - glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, - blend.src_a_func, blend.dst_a_func); + blend.dst_rgb_func != cur_state.blend.dst_rgb_func || + blend.src_a_func != cur_state.blend.src_a_func || + blend.dst_a_func != cur_state.blend.dst_a_func) { + glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, blend.src_a_func, + blend.dst_a_func); } if (blend.rgb_equation != cur_state.blend.rgb_equation || - blend.a_equation != cur_state.blend.a_equation) { + blend.a_equation != cur_state.blend.a_equation) { glBlendEquationSeparate(blend.rgb_equation, blend.a_equation); } @@ -237,8 +237,11 @@ void OpenGLState::Apply() const { GLenum OpenGLState::CheckFBStatus(GLenum target) { GLenum fb_status = glCheckFramebufferStatus(target); if (fb_status != GL_FRAMEBUFFER_COMPLETE) { - const char* fb_description = (target == GL_READ_FRAMEBUFFER ? "READ" : (target == GL_DRAW_FRAMEBUFFER ? "DRAW" : "UNK")); - LOG_CRITICAL(Render_OpenGL, "OpenGL %s framebuffer check failed, status %X", fb_description, fb_status); + const char* fb_description = + (target == GL_READ_FRAMEBUFFER ? "READ" + : (target == GL_DRAW_FRAMEBUFFER ? "DRAW" : "UNK")); + LOG_CRITICAL(Render_OpenGL, "OpenGL %s framebuffer check failed, status %X", fb_description, + fb_status); } return fb_status; diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index 13c71b0a6..01dead883 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h @@ -9,14 +9,14 @@ class OpenGLState { public: struct { - bool enabled; // GL_CULL_FACE - GLenum mode; // GL_CULL_FACE_MODE + bool enabled; // GL_CULL_FACE + GLenum mode; // GL_CULL_FACE_MODE GLenum front_face; // GL_FRONT_FACE } cull; struct { - bool test_enabled; // GL_DEPTH_TEST - GLenum test_func; // GL_DEPTH_FUNC + bool test_enabled; // GL_DEPTH_TEST + GLenum test_func; // GL_DEPTH_FUNC GLboolean write_mask; // GL_DEPTH_WRITEMASK } depth; @@ -28,24 +28,24 @@ public: } color_mask; // GL_COLOR_WRITEMASK struct { - bool test_enabled; // GL_STENCIL_TEST - GLenum test_func; // GL_STENCIL_FUNC - GLint test_ref; // GL_STENCIL_REF - GLuint test_mask; // GL_STENCIL_VALUE_MASK - GLuint write_mask; // GL_STENCIL_WRITEMASK + bool test_enabled; // GL_STENCIL_TEST + GLenum test_func; // GL_STENCIL_FUNC + GLint test_ref; // GL_STENCIL_REF + GLuint test_mask; // GL_STENCIL_VALUE_MASK + GLuint write_mask; // GL_STENCIL_WRITEMASK GLenum action_stencil_fail; // GL_STENCIL_FAIL - GLenum action_depth_fail; // GL_STENCIL_PASS_DEPTH_FAIL - GLenum action_depth_pass; // GL_STENCIL_PASS_DEPTH_PASS + GLenum action_depth_fail; // GL_STENCIL_PASS_DEPTH_FAIL + GLenum action_depth_pass; // GL_STENCIL_PASS_DEPTH_PASS } stencil; struct { - bool enabled; // GL_BLEND + bool enabled; // GL_BLEND GLenum rgb_equation; // GL_BLEND_EQUATION_RGB - GLenum a_equation; // GL_BLEND_EQUATION_ALPHA + GLenum a_equation; // GL_BLEND_EQUATION_ALPHA GLenum src_rgb_func; // GL_BLEND_SRC_RGB GLenum dst_rgb_func; // GL_BLEND_DST_RGB - GLenum src_a_func; // GL_BLEND_SRC_ALPHA - GLenum dst_a_func; // GL_BLEND_DST_ALPHA + GLenum src_a_func; // GL_BLEND_SRC_ALPHA + GLenum dst_a_func; // GL_BLEND_DST_ALPHA struct { GLclampf red; @@ -60,7 +60,7 @@ public: // 3 texture units - one for each that is used in PICA fragment shader emulation struct { GLuint texture_2d; // GL_TEXTURE_BINDING_2D - GLuint sampler; // GL_SAMPLER_BINDING + GLuint sampler; // GL_SAMPLER_BINDING } texture_units[3]; struct { @@ -74,10 +74,10 @@ public: struct { GLuint read_framebuffer; // GL_READ_FRAMEBUFFER_BINDING GLuint draw_framebuffer; // GL_DRAW_FRAMEBUFFER_BINDING - GLuint vertex_array; // GL_VERTEX_ARRAY_BINDING - GLuint vertex_buffer; // GL_ARRAY_BUFFER_BINDING - GLuint uniform_buffer; // GL_UNIFORM_BUFFER_BINDING - GLuint shader_program; // GL_CURRENT_PROGRAM + GLuint vertex_array; // GL_VERTEX_ARRAY_BINDING + GLuint vertex_buffer; // GL_ARRAY_BUFFER_BINDING + GLuint uniform_buffer; // GL_UNIFORM_BUFFER_BINDING + GLuint shader_program; // GL_CURRENT_PROGRAM } draw; OpenGLState(); diff --git a/src/video_core/renderer_opengl/pica_to_gl.h b/src/video_core/renderer_opengl/pica_to_gl.h index d9b9c9cc2..a604e94d4 100644 --- a/src/video_core/renderer_opengl/pica_to_gl.h +++ b/src/video_core/renderer_opengl/pica_to_gl.h @@ -25,8 +25,8 @@ namespace PicaToGL { inline GLenum TextureFilterMode(Pica::Regs::TextureConfig::TextureFilter mode) { static const GLenum filter_mode_table[] = { - GL_NEAREST, // TextureFilter::Nearest - GL_LINEAR // TextureFilter::Linear + GL_NEAREST, // TextureFilter::Nearest + GL_LINEAR // TextureFilter::Linear }; // Range check table for input @@ -52,10 +52,10 @@ inline GLenum TextureFilterMode(Pica::Regs::TextureConfig::TextureFilter mode) { inline GLenum WrapMode(Pica::Regs::TextureConfig::WrapMode mode) { static const GLenum wrap_mode_table[] = { - GL_CLAMP_TO_EDGE, // WrapMode::ClampToEdge - GL_CLAMP_TO_BORDER,// WrapMode::ClampToBorder - GL_REPEAT, // WrapMode::Repeat - GL_MIRRORED_REPEAT // WrapMode::MirroredRepeat + GL_CLAMP_TO_EDGE, // WrapMode::ClampToEdge + GL_CLAMP_TO_BORDER, // WrapMode::ClampToBorder + GL_REPEAT, // WrapMode::Repeat + GL_MIRRORED_REPEAT // WrapMode::MirroredRepeat }; // Range check table for input @@ -131,22 +131,22 @@ inline GLenum BlendFunc(Pica::Regs::BlendFactor factor) { inline GLenum LogicOp(Pica::Regs::LogicOp op) { static const GLenum logic_op_table[] = { - GL_CLEAR, // Clear - GL_AND, // And - GL_AND_REVERSE, // AndReverse - GL_COPY, // Copy - GL_SET, // Set - GL_COPY_INVERTED, // CopyInverted - GL_NOOP, // NoOp - GL_INVERT, // Invert - GL_NAND, // Nand - GL_OR, // Or - GL_NOR, // Nor - GL_XOR, // Xor - GL_EQUIV, // Equiv - GL_AND_INVERTED, // AndInverted - GL_OR_REVERSE, // OrReverse - GL_OR_INVERTED, // OrInverted + GL_CLEAR, // Clear + GL_AND, // And + GL_AND_REVERSE, // AndReverse + GL_COPY, // Copy + GL_SET, // Set + GL_COPY_INVERTED, // CopyInverted + GL_NOOP, // NoOp + GL_INVERT, // Invert + GL_NAND, // Nand + GL_OR, // Or + GL_NOR, // Nor + GL_XOR, // Xor + GL_EQUIV, // Equiv + GL_AND_INVERTED, // AndInverted + GL_OR_REVERSE, // OrReverse + GL_OR_INVERTED, // OrInverted }; // Range check table for input @@ -185,14 +185,14 @@ inline GLenum CompareFunc(Pica::Regs::CompareFunc func) { inline GLenum StencilOp(Pica::Regs::StencilAction action) { static const GLenum stencil_op_table[] = { - GL_KEEP, // StencilAction::Keep - GL_ZERO, // StencilAction::Zero - GL_REPLACE, // StencilAction::Replace - GL_INCR, // StencilAction::Increment - GL_DECR, // StencilAction::Decrement - GL_INVERT, // StencilAction::Invert - GL_INCR_WRAP, // StencilAction::IncrementWrap - GL_DECR_WRAP // StencilAction::DecrementWrap + GL_KEEP, // StencilAction::Keep + GL_ZERO, // StencilAction::Zero + GL_REPLACE, // StencilAction::Replace + GL_INCR, // StencilAction::Increment + GL_DECR, // StencilAction::Decrement + GL_INVERT, // StencilAction::Invert + GL_INCR_WRAP, // StencilAction::IncrementWrap + GL_DECR_WRAP // StencilAction::DecrementWrap }; // Range check table for input @@ -207,18 +207,12 @@ inline GLenum StencilOp(Pica::Regs::StencilAction action) { } inline GLvec4 ColorRGBA8(const u32 color) { - return { { (color >> 0 & 0xFF) / 255.0f, - (color >> 8 & 0xFF) / 255.0f, - (color >> 16 & 0xFF) / 255.0f, - (color >> 24 & 0xFF) / 255.0f - } }; + return {{(color >> 0 & 0xFF) / 255.0f, (color >> 8 & 0xFF) / 255.0f, + (color >> 16 & 0xFF) / 255.0f, (color >> 24 & 0xFF) / 255.0f}}; } inline std::array<GLfloat, 3> LightColor(const Pica::Regs::LightColor& color) { - return { { color.r / 255.0f, - color.g / 255.0f, - color.b / 255.0f - } }; + return {{color.r / 255.0f, color.g / 255.0f, color.b / 255.0f}}; } } // namespace diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 8410e0a64..3cabda8f9 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -89,8 +89,12 @@ struct ScreenRectVertex { static std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(const float width, const float height) { std::array<GLfloat, 3 * 2> matrix; - matrix[0] = 2.f / width; matrix[2] = 0.f; matrix[4] = -1.f; - matrix[1] = 0.f; matrix[3] = -2.f / height; matrix[5] = 1.f; + matrix[0] = 2.f / width; + matrix[2] = 0.f; + matrix[4] = -1.f; + matrix[1] = 0.f; + matrix[3] = -2.f / height; + matrix[5] = 1.f; // Last matrix row is implicitly assumed to be [0, 0, 1]. return matrix; @@ -98,7 +102,7 @@ static std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(const float width, cons /// RendererOpenGL constructor RendererOpenGL::RendererOpenGL() { - resolution_width = std::max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth); + resolution_width = std::max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth); resolution_height = VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight; } @@ -116,13 +120,15 @@ void RendererOpenGL::SwapBuffers() { const auto& framebuffer = GPU::g_regs.framebuffer_config[i]; // Main LCD (0): 0x1ED02204, Sub LCD (1): 0x1ED02A04 - u32 lcd_color_addr = (i == 0) ? LCD_REG_INDEX(color_fill_top) : LCD_REG_INDEX(color_fill_bottom); + u32 lcd_color_addr = + (i == 0) ? LCD_REG_INDEX(color_fill_top) : LCD_REG_INDEX(color_fill_bottom); lcd_color_addr = HW::VADDR_LCD + 4 * lcd_color_addr; LCD::Regs::ColorFill color_fill = {0}; LCD::Read(color_fill.raw, lcd_color_addr); if (color_fill.is_enabled) { - LoadColorToActiveGLTexture(color_fill.color_r, color_fill.color_g, color_fill.color_b, screen_infos[i].texture); + LoadColorToActiveGLTexture(color_fill.color_r, color_fill.color_g, color_fill.color_b, + screen_infos[i].texture); // Resize the texture in case the framebuffer size has changed screen_infos[i].texture.width = 1; @@ -172,15 +178,14 @@ void RendererOpenGL::SwapBuffers() { * Loads framebuffer from emulated memory into the active OpenGL texture. */ void RendererOpenGL::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& framebuffer, - ScreenInfo& screen_info) { + ScreenInfo& screen_info) { - const PAddr framebuffer_addr = framebuffer.active_fb == 0 ? - framebuffer.address_left1 : framebuffer.address_left2; + const PAddr framebuffer_addr = + framebuffer.active_fb == 0 ? framebuffer.address_left1 : framebuffer.address_left2; LOG_TRACE(Render_OpenGL, "0x%08x bytes from 0x%08x(%dx%d), fmt %x", - framebuffer.stride * framebuffer.height, - framebuffer_addr, (int)framebuffer.width, - (int)framebuffer.height, (int)framebuffer.format); + framebuffer.stride * framebuffer.height, framebuffer_addr, (int)framebuffer.width, + (int)framebuffer.height, (int)framebuffer.format); int bpp = GPU::Regs::BytesPerPixel(framebuffer.color_format); size_t pixel_stride = framebuffer.stride / bpp; @@ -192,7 +197,8 @@ void RendererOpenGL::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& fram // only allows rows to have a memory alignement of 4. ASSERT(pixel_stride % 4 == 0); - if (!Rasterizer()->AccelerateDisplay(framebuffer, framebuffer_addr, static_cast<u32>(pixel_stride), screen_info)) { + if (!Rasterizer()->AccelerateDisplay(framebuffer, framebuffer_addr, + static_cast<u32>(pixel_stride), screen_info)) { // Reset the screen info's display texture to its own permanent texture screen_info.display_texture = screen_info.texture.resource.handle; screen_info.display_texcoords = MathUtil::Rectangle<float>(0.f, 0.f, 1.f, 1.f); @@ -208,12 +214,14 @@ void RendererOpenGL::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& fram glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)pixel_stride); // Update existing texture - // TODO: Test what happens on hardware when you change the framebuffer dimensions so that they + // TODO: Test what happens on hardware when you change the framebuffer dimensions so that + // they // differ from the LCD resolution. // TODO: Applications could theoretically crash Citra here by specifying too large // framebuffer sizes. We should make sure that this cannot happen. glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, framebuffer.width, framebuffer.height, - screen_info.texture.gl_format, screen_info.texture.gl_type, framebuffer_data); + screen_info.texture.gl_format, screen_info.texture.gl_type, + framebuffer_data); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); @@ -224,7 +232,8 @@ void RendererOpenGL::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& fram /** * Fills active OpenGL texture with the given RGB color. - * Since the color is solid, the texture can be 1x1 but will stretch across whatever it's rendered on. + * Since the color is solid, the texture can be 1x1 but will stretch across whatever it's rendered + * on. * This has the added benefit of being *really fast*. */ void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, @@ -233,7 +242,7 @@ void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color state.Apply(); glActiveTexture(GL_TEXTURE0); - u8 framebuffer_data[3] = { color_r, color_g, color_b }; + u8 framebuffer_data[3] = {color_r, color_g, color_b}; // Update existing texture glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, framebuffer_data); @@ -246,7 +255,8 @@ void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color * Initializes the OpenGL state and creates persistent objects. */ void RendererOpenGL::InitOpenGLObjects() { - glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, 0.0f); + glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, + 0.0f); // Link shaders and get variable locations shader.Create(vertex_shader, fragment_shader); @@ -270,8 +280,10 @@ void RendererOpenGL::InitOpenGLObjects() { // Attach vertex data to VAO glBufferData(GL_ARRAY_BUFFER, sizeof(ScreenRectVertex) * 4, nullptr, GL_STREAM_DRAW); - glVertexAttribPointer(attrib_position, 2, GL_FLOAT, GL_FALSE, sizeof(ScreenRectVertex), (GLvoid*)offsetof(ScreenRectVertex, position)); - glVertexAttribPointer(attrib_tex_coord, 2, GL_FLOAT, GL_FALSE, sizeof(ScreenRectVertex), (GLvoid*)offsetof(ScreenRectVertex, tex_coord)); + glVertexAttribPointer(attrib_position, 2, GL_FLOAT, GL_FALSE, sizeof(ScreenRectVertex), + (GLvoid*)offsetof(ScreenRectVertex, position)); + glVertexAttribPointer(attrib_tex_coord, 2, GL_FLOAT, GL_FALSE, sizeof(ScreenRectVertex), + (GLvoid*)offsetof(ScreenRectVertex, tex_coord)); glEnableVertexAttribArray(attrib_position); glEnableVertexAttribArray(attrib_tex_coord); @@ -352,23 +364,25 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, glActiveTexture(GL_TEXTURE0); glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0, - texture.gl_format, texture.gl_type, nullptr); + texture.gl_format, texture.gl_type, nullptr); state.texture_units[0].texture_2d = 0; state.Apply(); } /** - * Draws a single texture to the emulator window, rotating the texture to correct for the 3DS's LCD rotation. + * Draws a single texture to the emulator window, rotating the texture to correct for the 3DS's LCD + * rotation. */ -void RendererOpenGL::DrawSingleScreenRotated(const ScreenInfo& screen_info, float x, float y, float w, float h) { +void RendererOpenGL::DrawSingleScreenRotated(const ScreenInfo& screen_info, float x, float y, + float w, float h) { auto& texcoords = screen_info.display_texcoords; std::array<ScreenRectVertex, 4> vertices = {{ - ScreenRectVertex(x, y, texcoords.bottom, texcoords.left), - ScreenRectVertex(x+w, y, texcoords.bottom, texcoords.right), - ScreenRectVertex(x, y+h, texcoords.top, texcoords.left), - ScreenRectVertex(x+w, y+h, texcoords.top, texcoords.right), + ScreenRectVertex(x, y, texcoords.bottom, texcoords.left), + ScreenRectVertex(x + w, y, texcoords.bottom, texcoords.right), + ScreenRectVertex(x, y + h, texcoords.top, texcoords.left), + ScreenRectVertex(x + w, y + h, texcoords.top, texcoords.right), }}; state.texture_units[0].texture_2d = screen_info.display_texture; @@ -391,18 +405,20 @@ void RendererOpenGL::DrawScreens() { glClear(GL_COLOR_BUFFER_BIT); // Set projection matrix - std::array<GLfloat, 3 * 2> ortho_matrix = MakeOrthographicMatrix((float)layout.width, - (float)layout.height); + std::array<GLfloat, 3 * 2> ortho_matrix = + MakeOrthographicMatrix((float)layout.width, (float)layout.height); glUniformMatrix3x2fv(uniform_modelview_matrix, 1, GL_FALSE, ortho_matrix.data()); // Bind texture in Texture Unit 0 glActiveTexture(GL_TEXTURE0); glUniform1i(uniform_color_texture, 0); - DrawSingleScreenRotated(screen_infos[0], (float)layout.top_screen.left, (float)layout.top_screen.top, - (float)layout.top_screen.GetWidth(), (float)layout.top_screen.GetHeight()); - DrawSingleScreenRotated(screen_infos[1], (float)layout.bottom_screen.left,(float)layout.bottom_screen.top, - (float)layout.bottom_screen.GetWidth(), (float)layout.bottom_screen.GetHeight()); + DrawSingleScreenRotated(screen_infos[0], (float)layout.top_screen.left, + (float)layout.top_screen.top, (float)layout.top_screen.GetWidth(), + (float)layout.top_screen.GetHeight()); + DrawSingleScreenRotated(screen_infos[1], (float)layout.bottom_screen.left, + (float)layout.bottom_screen.top, (float)layout.bottom_screen.GetWidth(), + (float)layout.bottom_screen.GetHeight()); m_current_frame++; } @@ -420,14 +436,16 @@ void RendererOpenGL::SetWindow(EmuWindow* window) { } static const char* GetSource(GLenum source) { -#define RET(s) case GL_DEBUG_SOURCE_##s: return #s +#define RET(s) \ + case GL_DEBUG_SOURCE_##s: \ + return #s switch (source) { - RET(API); - RET(WINDOW_SYSTEM); - RET(SHADER_COMPILER); - RET(THIRD_PARTY); - RET(APPLICATION); - RET(OTHER); + RET(API); + RET(WINDOW_SYSTEM); + RET(SHADER_COMPILER); + RET(THIRD_PARTY); + RET(APPLICATION); + RET(OTHER); default: UNREACHABLE(); } @@ -435,23 +453,25 @@ static const char* GetSource(GLenum source) { } static const char* GetType(GLenum type) { -#define RET(t) case GL_DEBUG_TYPE_##t: return #t +#define RET(t) \ + case GL_DEBUG_TYPE_##t: \ + return #t switch (type) { - RET(ERROR); - RET(DEPRECATED_BEHAVIOR); - RET(UNDEFINED_BEHAVIOR); - RET(PORTABILITY); - RET(PERFORMANCE); - RET(OTHER); - RET(MARKER); + RET(ERROR); + RET(DEPRECATED_BEHAVIOR); + RET(UNDEFINED_BEHAVIOR); + RET(PORTABILITY); + RET(PERFORMANCE); + RET(OTHER); + RET(MARKER); default: UNREACHABLE(); } #undef RET } -static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, - const GLchar* message, const void* user_param) { +static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum severity, + GLsizei length, const GLchar* message, const void* user_param) { Log::Level level; switch (severity) { case GL_DEBUG_SEVERITY_HIGH: @@ -465,8 +485,8 @@ static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum level = Log::Level::Debug; break; } - LOG_GENERIC(Log::Class::Render_OpenGL, level, "%s %s %d: %s", - GetSource(source), GetType(type), id, message); + LOG_GENERIC(Log::Class::Render_OpenGL, level, "%s %s %d: %s", GetSource(source), GetType(type), + id, message); } /// Initialize the renderer diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index 00e1044ab..faeb519ec 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h @@ -38,7 +38,6 @@ struct ScreenInfo { class RendererOpenGL : public RendererBase { public: - RendererOpenGL(); ~RendererOpenGL() override; @@ -67,15 +66,14 @@ private: // Loads framebuffer from emulated memory into the display information structure void LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& framebuffer, - ScreenInfo& screen_info); + ScreenInfo& screen_info); // Fills active OpenGL texture with the given RGB color. - void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, - const TextureInfo& texture); + void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, const TextureInfo& texture); - EmuWindow* render_window; ///< Handle to render window + EmuWindow* render_window; ///< Handle to render window - int resolution_width; ///< Current resolution width - int resolution_height; ///< Current resolution height + int resolution_width; ///< Current resolution width + int resolution_height; ///< Current resolution height OpenGLState state; @@ -83,7 +81,8 @@ private: OGLVertexArray vertex_array; OGLBuffer vertex_buffer; OGLShader shader; - std::array<ScreenInfo, 2> screen_infos; ///< Display information for top and bottom screens respectively + std::array<ScreenInfo, 2> + screen_infos; ///< Display information for top and bottom screens respectively // Shader uniform location indices GLuint uniform_modelview_matrix; GLuint uniform_color_texture; |