diff options
| author | 2016-09-18 09:38:01 +0900 | |
|---|---|---|
| committer | 2016-09-18 09:38:01 +0900 | |
| commit | dc8479928c5aee4c6ad6fe4f59006fb604cee701 (patch) | |
| tree | 569a7f13128450bbab973236615587ff00bced5f /src/video_core/renderer_opengl | |
| parent | Travis: Import Dolphin’s clang-format hook. (diff) | |
| download | yuzu-dc8479928c5aee4c6ad6fe4f59006fb604cee701.tar.gz yuzu-dc8479928c5aee4c6ad6fe4f59006fb604cee701.tar.xz yuzu-dc8479928c5aee4c6ad6fe4f59006fb604cee701.zip | |
Sources: Run clang-format on everything.
Diffstat (limited to 'src/video_core/renderer_opengl')
| -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) { | |||
| 32 | stage.alpha_source1 == Pica::Regs::TevStageConfig::Source::Previous && | 32 | stage.alpha_source1 == Pica::Regs::TevStageConfig::Source::Previous && |
| 33 | stage.color_modifier1 == Pica::Regs::TevStageConfig::ColorModifier::SourceColor && | 33 | stage.color_modifier1 == Pica::Regs::TevStageConfig::ColorModifier::SourceColor && |
| 34 | stage.alpha_modifier1 == Pica::Regs::TevStageConfig::AlphaModifier::SourceAlpha && | 34 | stage.alpha_modifier1 == Pica::Regs::TevStageConfig::AlphaModifier::SourceAlpha && |
| 35 | stage.GetColorMultiplier() == 1 && | 35 | stage.GetColorMultiplier() == 1 && stage.GetAlphaMultiplier() == 1); |
| 36 | stage.GetAlphaMultiplier() == 1); | ||
| 37 | } | 36 | } |
| 38 | 37 | ||
| 39 | RasterizerOpenGL::RasterizerOpenGL() : shader_dirty(true) { | 38 | RasterizerOpenGL::RasterizerOpenGL() : shader_dirty(true) { |
| @@ -65,26 +64,34 @@ RasterizerOpenGL::RasterizerOpenGL() : shader_dirty(true) { | |||
| 65 | uniform_block_data.fog_lut_dirty = true; | 64 | uniform_block_data.fog_lut_dirty = true; |
| 66 | 65 | ||
| 67 | // Set vertex attributes | 66 | // Set vertex attributes |
| 68 | glVertexAttribPointer(GLShader::ATTRIBUTE_POSITION, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, position)); | 67 | glVertexAttribPointer(GLShader::ATTRIBUTE_POSITION, 4, GL_FLOAT, GL_FALSE, |
| 68 | sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, position)); | ||
| 69 | glEnableVertexAttribArray(GLShader::ATTRIBUTE_POSITION); | 69 | glEnableVertexAttribArray(GLShader::ATTRIBUTE_POSITION); |
| 70 | 70 | ||
| 71 | glVertexAttribPointer(GLShader::ATTRIBUTE_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, color)); | 71 | glVertexAttribPointer(GLShader::ATTRIBUTE_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), |
| 72 | (GLvoid*)offsetof(HardwareVertex, color)); | ||
| 72 | glEnableVertexAttribArray(GLShader::ATTRIBUTE_COLOR); | 73 | glEnableVertexAttribArray(GLShader::ATTRIBUTE_COLOR); |
| 73 | 74 | ||
| 74 | glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD0, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0)); | 75 | glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD0, 2, GL_FLOAT, GL_FALSE, |
| 75 | glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD1, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord1)); | 76 | sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0)); |
| 76 | glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD2, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord2)); | 77 | glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD1, 2, GL_FLOAT, GL_FALSE, |
| 78 | sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord1)); | ||
| 79 | glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD2, 2, GL_FLOAT, GL_FALSE, | ||
| 80 | sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord2)); | ||
| 77 | glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD0); | 81 | glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD0); |
| 78 | glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD1); | 82 | glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD1); |
| 79 | glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD2); | 83 | glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD2); |
| 80 | 84 | ||
| 81 | glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD0_W, 1, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0_w)); | 85 | glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD0_W, 1, GL_FLOAT, GL_FALSE, |
| 86 | sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0_w)); | ||
| 82 | glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD0_W); | 87 | glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD0_W); |
| 83 | 88 | ||
| 84 | glVertexAttribPointer(GLShader::ATTRIBUTE_NORMQUAT, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, normquat)); | 89 | glVertexAttribPointer(GLShader::ATTRIBUTE_NORMQUAT, 4, GL_FLOAT, GL_FALSE, |
| 90 | sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, normquat)); | ||
| 85 | glEnableVertexAttribArray(GLShader::ATTRIBUTE_NORMQUAT); | 91 | glEnableVertexAttribArray(GLShader::ATTRIBUTE_NORMQUAT); |
| 86 | 92 | ||
| 87 | glVertexAttribPointer(GLShader::ATTRIBUTE_VIEW, 3, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, view)); | 93 | glVertexAttribPointer(GLShader::ATTRIBUTE_VIEW, 3, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), |
| 94 | (GLvoid*)offsetof(HardwareVertex, view)); | ||
| 88 | glEnableVertexAttribArray(GLShader::ATTRIBUTE_VIEW); | 95 | glEnableVertexAttribArray(GLShader::ATTRIBUTE_VIEW); |
| 89 | 96 | ||
| 90 | // Create render framebuffer | 97 | // Create render framebuffer |
| @@ -130,7 +137,6 @@ RasterizerOpenGL::RasterizerOpenGL() : shader_dirty(true) { | |||
| 130 | } | 137 | } |
| 131 | 138 | ||
| 132 | RasterizerOpenGL::~RasterizerOpenGL() { | 139 | RasterizerOpenGL::~RasterizerOpenGL() { |
| 133 | |||
| 134 | } | 140 | } |
| 135 | 141 | ||
| 136 | /** | 142 | /** |
| @@ -149,8 +155,8 @@ RasterizerOpenGL::~RasterizerOpenGL() { | |||
| 149 | * manually using two Lerps, and doing this correction before each Lerp. | 155 | * manually using two Lerps, and doing this correction before each Lerp. |
| 150 | */ | 156 | */ |
| 151 | static bool AreQuaternionsOpposite(Math::Vec4<Pica::float24> qa, Math::Vec4<Pica::float24> qb) { | 157 | static bool AreQuaternionsOpposite(Math::Vec4<Pica::float24> qa, Math::Vec4<Pica::float24> qb) { |
| 152 | Math::Vec4f a{ qa.x.ToFloat32(), qa.y.ToFloat32(), qa.z.ToFloat32(), qa.w.ToFloat32() }; | 158 | Math::Vec4f a{qa.x.ToFloat32(), qa.y.ToFloat32(), qa.z.ToFloat32(), qa.w.ToFloat32()}; |
| 153 | Math::Vec4f b{ qb.x.ToFloat32(), qb.y.ToFloat32(), qb.z.ToFloat32(), qb.w.ToFloat32() }; | 159 | Math::Vec4f b{qb.x.ToFloat32(), qb.y.ToFloat32(), qb.z.ToFloat32(), qb.w.ToFloat32()}; |
| 154 | 160 | ||
| 155 | return (Math::Dot(a, b) < 0.f); | 161 | return (Math::Dot(a, b) < 0.f); |
| 156 | } | 162 | } |
| @@ -173,15 +179,20 @@ void RasterizerOpenGL::DrawTriangles() { | |||
| 173 | CachedSurface* color_surface; | 179 | CachedSurface* color_surface; |
| 174 | CachedSurface* depth_surface; | 180 | CachedSurface* depth_surface; |
| 175 | MathUtil::Rectangle<int> rect; | 181 | MathUtil::Rectangle<int> rect; |
| 176 | std::tie(color_surface, depth_surface, rect) = res_cache.GetFramebufferSurfaces(regs.framebuffer); | 182 | std::tie(color_surface, depth_surface, rect) = |
| 183 | res_cache.GetFramebufferSurfaces(regs.framebuffer); | ||
| 177 | 184 | ||
| 178 | state.draw.draw_framebuffer = framebuffer.handle; | 185 | state.draw.draw_framebuffer = framebuffer.handle; |
| 179 | state.Apply(); | 186 | state.Apply(); |
| 180 | 187 | ||
| 181 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color_surface != nullptr ? color_surface->texture.handle : 0, 0); | 188 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| 182 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_surface != nullptr ? depth_surface->texture.handle : 0, 0); | 189 | color_surface != nullptr ? color_surface->texture.handle : 0, 0); |
| 190 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, | ||
| 191 | depth_surface != nullptr ? depth_surface->texture.handle : 0, 0); | ||
| 183 | bool has_stencil = regs.framebuffer.depth_format == Pica::Regs::DepthFormat::D24S8; | 192 | bool has_stencil = regs.framebuffer.depth_format == Pica::Regs::DepthFormat::D24S8; |
| 184 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, (has_stencil && depth_surface != nullptr) ? depth_surface->texture.handle : 0, 0); | 193 | glFramebufferTexture2D( |
| 194 | GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, | ||
| 195 | (has_stencil && depth_surface != nullptr) ? depth_surface->texture.handle : 0, 0); | ||
| 185 | 196 | ||
| 186 | if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { | 197 | if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { |
| 187 | return; | 198 | return; |
| @@ -194,7 +205,8 @@ void RasterizerOpenGL::DrawTriangles() { | |||
| 194 | 205 | ||
| 195 | glViewport((GLint)(rect.left + regs.viewport_corner.x * color_surface->res_scale_width), | 206 | glViewport((GLint)(rect.left + regs.viewport_corner.x * color_surface->res_scale_width), |
| 196 | (GLint)(rect.bottom + regs.viewport_corner.y * color_surface->res_scale_height), | 207 | (GLint)(rect.bottom + regs.viewport_corner.y * color_surface->res_scale_height), |
| 197 | (GLsizei)(viewport_width * color_surface->res_scale_width), (GLsizei)(viewport_height * color_surface->res_scale_height)); | 208 | (GLsizei)(viewport_width * color_surface->res_scale_width), |
| 209 | (GLsizei)(viewport_height * color_surface->res_scale_height)); | ||
| 198 | 210 | ||
| 199 | if (uniform_block_data.data.framebuffer_scale[0] != color_surface->res_scale_width || | 211 | if (uniform_block_data.data.framebuffer_scale[0] != color_surface->res_scale_width || |
| 200 | uniform_block_data.data.framebuffer_scale[1] != color_surface->res_scale_height) { | 212 | uniform_block_data.data.framebuffer_scale[1] != color_surface->res_scale_height) { |
| @@ -245,14 +257,16 @@ void RasterizerOpenGL::DrawTriangles() { | |||
| 245 | 257 | ||
| 246 | // Sync the uniform data | 258 | // Sync the uniform data |
| 247 | if (uniform_block_data.dirty) { | 259 | if (uniform_block_data.dirty) { |
| 248 | glBufferData(GL_UNIFORM_BUFFER, sizeof(UniformData), &uniform_block_data.data, GL_STATIC_DRAW); | 260 | glBufferData(GL_UNIFORM_BUFFER, sizeof(UniformData), &uniform_block_data.data, |
| 261 | GL_STATIC_DRAW); | ||
| 249 | uniform_block_data.dirty = false; | 262 | uniform_block_data.dirty = false; |
| 250 | } | 263 | } |
| 251 | 264 | ||
| 252 | state.Apply(); | 265 | state.Apply(); |
| 253 | 266 | ||
| 254 | // Draw the vertex batch | 267 | // Draw the vertex batch |
| 255 | glBufferData(GL_ARRAY_BUFFER, vertex_batch.size() * sizeof(HardwareVertex), vertex_batch.data(), GL_STREAM_DRAW); | 268 | glBufferData(GL_ARRAY_BUFFER, vertex_batch.size() * sizeof(HardwareVertex), vertex_batch.data(), |
| 269 | GL_STREAM_DRAW); | ||
| 256 | glDrawArrays(GL_TRIANGLES, 0, (GLsizei)vertex_batch.size()); | 270 | glDrawArrays(GL_TRIANGLES, 0, (GLsizei)vertex_batch.size()); |
| 257 | 271 | ||
| 258 | // Mark framebuffer surfaces as dirty | 272 | // Mark framebuffer surfaces as dirty |
| @@ -278,7 +292,7 @@ void RasterizerOpenGL::DrawTriangles() { | |||
| 278 | void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { | 292 | void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { |
| 279 | const auto& regs = Pica::g_state.regs; | 293 | const auto& regs = Pica::g_state.regs; |
| 280 | 294 | ||
| 281 | switch(id) { | 295 | switch (id) { |
| 282 | // Culling | 296 | // Culling |
| 283 | case PICA_REG_INDEX(cull_mode): | 297 | case PICA_REG_INDEX(cull_mode): |
| 284 | SyncCullMode(); | 298 | SyncCullMode(); |
| @@ -548,7 +562,7 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { | |||
| 548 | SyncLightAmbient(7); | 562 | SyncLightAmbient(7); |
| 549 | break; | 563 | break; |
| 550 | 564 | ||
| 551 | // Fragment lighting position | 565 | // Fragment lighting position |
| 552 | case PICA_REG_INDEX_WORKAROUND(lighting.light[0].x, 0x144 + 0 * 0x10): | 566 | case PICA_REG_INDEX_WORKAROUND(lighting.light[0].x, 0x144 + 0 * 0x10): |
| 553 | case PICA_REG_INDEX_WORKAROUND(lighting.light[0].z, 0x145 + 0 * 0x10): | 567 | case PICA_REG_INDEX_WORKAROUND(lighting.light[0].z, 0x145 + 0 * 0x10): |
| 554 | SyncLightPosition(0); | 568 | SyncLightPosition(0); |
| @@ -659,13 +673,11 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { | |||
| 659 | case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[4], 0x1cc): | 673 | case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[4], 0x1cc): |
| 660 | case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[5], 0x1cd): | 674 | case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[5], 0x1cd): |
| 661 | case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[6], 0x1ce): | 675 | case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[6], 0x1ce): |
| 662 | case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[7], 0x1cf): | 676 | case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[7], 0x1cf): { |
| 663 | { | ||
| 664 | auto& lut_config = regs.lighting.lut_config; | 677 | auto& lut_config = regs.lighting.lut_config; |
| 665 | uniform_block_data.lut_dirty[lut_config.type / 4] = true; | 678 | uniform_block_data.lut_dirty[lut_config.type / 4] = true; |
| 666 | break; | 679 | break; |
| 667 | } | 680 | } |
| 668 | |||
| 669 | } | 681 | } |
| 670 | } | 682 | } |
| 671 | 683 | ||
| @@ -699,8 +711,10 @@ bool RasterizerOpenGL::AccelerateDisplayTransfer(const GPU::Regs::DisplayTransfe | |||
| 699 | 711 | ||
| 700 | CachedSurface dst_params; | 712 | CachedSurface dst_params; |
| 701 | dst_params.addr = config.GetPhysicalOutputAddress(); | 713 | dst_params.addr = config.GetPhysicalOutputAddress(); |
| 702 | dst_params.width = config.scaling != config.NoScale ? config.output_width / 2 : config.output_width.Value(); | 714 | dst_params.width = |
| 703 | dst_params.height = config.scaling == config.ScaleXY ? config.output_height / 2 : config.output_height.Value(); | 715 | config.scaling != config.NoScale ? config.output_width / 2 : config.output_width.Value(); |
| 716 | dst_params.height = | ||
| 717 | config.scaling == config.ScaleXY ? config.output_height / 2 : config.output_height.Value(); | ||
| 704 | dst_params.is_tiled = config.input_linear != config.dont_swizzle; | 718 | dst_params.is_tiled = config.input_linear != config.dont_swizzle; |
| 705 | dst_params.pixel_format = CachedSurface::PixelFormatFromGPUPixelFormat(config.output_format); | 719 | dst_params.pixel_format = CachedSurface::PixelFormatFromGPUPixelFormat(config.output_format); |
| 706 | 720 | ||
| @@ -735,7 +749,8 @@ bool RasterizerOpenGL::AccelerateDisplayTransfer(const GPU::Regs::DisplayTransfe | |||
| 735 | return false; | 749 | return false; |
| 736 | } | 750 | } |
| 737 | 751 | ||
| 738 | u32 dst_size = dst_params.width * dst_params.height * CachedSurface::GetFormatBpp(dst_params.pixel_format) / 8; | 752 | u32 dst_size = dst_params.width * dst_params.height * |
| 753 | CachedSurface::GetFormatBpp(dst_params.pixel_format) / 8; | ||
| 739 | dst_surface->dirty = true; | 754 | dst_surface->dirty = true; |
| 740 | res_cache.FlushRegion(config.GetPhysicalOutputAddress(), dst_size, dst_surface, true); | 755 | res_cache.FlushRegion(config.GetPhysicalOutputAddress(), dst_size, dst_surface, true); |
| 741 | return true; | 756 | return true; |
| @@ -757,12 +772,15 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config) | |||
| 757 | 772 | ||
| 758 | GLuint old_fb = cur_state.draw.draw_framebuffer; | 773 | GLuint old_fb = cur_state.draw.draw_framebuffer; |
| 759 | cur_state.draw.draw_framebuffer = framebuffer.handle; | 774 | cur_state.draw.draw_framebuffer = framebuffer.handle; |
| 760 | // TODO: When scissor test is implemented, need to disable scissor test in cur_state here so Clear call isn't affected | 775 | // TODO: When scissor test is implemented, need to disable scissor test in cur_state here so |
| 776 | // Clear call isn't affected | ||
| 761 | cur_state.Apply(); | 777 | cur_state.Apply(); |
| 762 | 778 | ||
| 763 | if (dst_type == SurfaceType::Color || dst_type == SurfaceType::Texture) { | 779 | if (dst_type == SurfaceType::Color || dst_type == SurfaceType::Texture) { |
| 764 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dst_surface->texture.handle, 0); | 780 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| 765 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); | 781 | dst_surface->texture.handle, 0); |
| 782 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, | ||
| 783 | 0); | ||
| 766 | 784 | ||
| 767 | if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { | 785 | if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { |
| 768 | return false; | 786 | return false; |
| @@ -770,8 +788,10 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config) | |||
| 770 | 788 | ||
| 771 | GLfloat color_values[4] = {0.0f, 0.0f, 0.0f, 0.0f}; | 789 | GLfloat color_values[4] = {0.0f, 0.0f, 0.0f, 0.0f}; |
| 772 | 790 | ||
| 773 | // TODO: Handle additional pixel format and fill value size combinations to accelerate more cases | 791 | // TODO: Handle additional pixel format and fill value size combinations to accelerate more |
| 774 | // For instance, checking if fill value's bytes/bits repeat to allow filling I8/A8/I4/A4/... | 792 | // cases |
| 793 | // For instance, checking if fill value's bytes/bits repeat to allow filling | ||
| 794 | // I8/A8/I4/A4/... | ||
| 775 | // Currently only handles formats that are multiples of the fill value size | 795 | // Currently only handles formats that are multiples of the fill value size |
| 776 | 796 | ||
| 777 | if (config.fill_24bit) { | 797 | if (config.fill_24bit) { |
| @@ -846,7 +866,8 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config) | |||
| 846 | glClearBufferfv(GL_COLOR, 0, color_values); | 866 | glClearBufferfv(GL_COLOR, 0, color_values); |
| 847 | } else if (dst_type == SurfaceType::Depth) { | 867 | } else if (dst_type == SurfaceType::Depth) { |
| 848 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); | 868 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); |
| 849 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, dst_surface->texture.handle, 0); | 869 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, |
| 870 | dst_surface->texture.handle, 0); | ||
| 850 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); | 871 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); |
| 851 | 872 | ||
| 852 | if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { | 873 | if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { |
| @@ -865,7 +886,8 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config) | |||
| 865 | glClearBufferfv(GL_DEPTH, 0, &value_float); | 886 | glClearBufferfv(GL_DEPTH, 0, &value_float); |
| 866 | } else if (dst_type == SurfaceType::DepthStencil) { | 887 | } else if (dst_type == SurfaceType::DepthStencil) { |
| 867 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); | 888 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); |
| 868 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, dst_surface->texture.handle, 0); | 889 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, |
| 890 | dst_surface->texture.handle, 0); | ||
| 869 | 891 | ||
| 870 | if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { | 892 | if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { |
| 871 | return false; | 893 | return false; |
| @@ -889,7 +911,9 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config) | |||
| 889 | return true; | 911 | return true; |
| 890 | } | 912 | } |
| 891 | 913 | ||
| 892 | bool RasterizerOpenGL::AccelerateDisplay(const GPU::Regs::FramebufferConfig& config, PAddr framebuffer_addr, u32 pixel_stride, ScreenInfo& screen_info) { | 914 | bool RasterizerOpenGL::AccelerateDisplay(const GPU::Regs::FramebufferConfig& config, |
| 915 | PAddr framebuffer_addr, u32 pixel_stride, | ||
| 916 | ScreenInfo& screen_info) { | ||
| 893 | if (framebuffer_addr == 0) { | 917 | if (framebuffer_addr == 0) { |
| 894 | return false; | 918 | return false; |
| 895 | } | 919 | } |
| @@ -912,10 +936,9 @@ bool RasterizerOpenGL::AccelerateDisplay(const GPU::Regs::FramebufferConfig& con | |||
| 912 | u32 scaled_width = src_surface->GetScaledWidth(); | 936 | u32 scaled_width = src_surface->GetScaledWidth(); |
| 913 | u32 scaled_height = src_surface->GetScaledHeight(); | 937 | u32 scaled_height = src_surface->GetScaledHeight(); |
| 914 | 938 | ||
| 915 | screen_info.display_texcoords = MathUtil::Rectangle<float>((float)src_rect.top / (float)scaled_height, | 939 | screen_info.display_texcoords = MathUtil::Rectangle<float>( |
| 916 | (float)src_rect.left / (float)scaled_width, | 940 | (float)src_rect.top / (float)scaled_height, (float)src_rect.left / (float)scaled_width, |
| 917 | (float)src_rect.bottom / (float)scaled_height, | 941 | (float)src_rect.bottom / (float)scaled_height, (float)src_rect.right / (float)scaled_width); |
| 918 | (float)src_rect.right / (float)scaled_width); | ||
| 919 | 942 | ||
| 920 | screen_info.display_texture = src_surface->texture.handle; | 943 | screen_info.display_texture = src_surface->texture.handle; |
| 921 | 944 | ||
| @@ -928,7 +951,8 @@ void RasterizerOpenGL::SamplerInfo::Create() { | |||
| 928 | wrap_s = wrap_t = TextureConfig::Repeat; | 951 | wrap_s = wrap_t = TextureConfig::Repeat; |
| 929 | border_color = 0; | 952 | border_color = 0; |
| 930 | 953 | ||
| 931 | glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // default is GL_LINEAR_MIPMAP_LINEAR | 954 | glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER, |
| 955 | GL_LINEAR); // default is GL_LINEAR_MIPMAP_LINEAR | ||
| 932 | // Other attributes have correct defaults | 956 | // Other attributes have correct defaults |
| 933 | } | 957 | } |
| 934 | 958 | ||
| @@ -976,41 +1000,64 @@ void RasterizerOpenGL::SetShader() { | |||
| 976 | } else { | 1000 | } else { |
| 977 | LOG_DEBUG(Render_OpenGL, "Creating new shader"); | 1001 | LOG_DEBUG(Render_OpenGL, "Creating new shader"); |
| 978 | 1002 | ||
| 979 | shader->shader.Create(GLShader::GenerateVertexShader().c_str(), GLShader::GenerateFragmentShader(config).c_str()); | 1003 | shader->shader.Create(GLShader::GenerateVertexShader().c_str(), |
| 1004 | GLShader::GenerateFragmentShader(config).c_str()); | ||
| 980 | 1005 | ||
| 981 | state.draw.shader_program = shader->shader.handle; | 1006 | state.draw.shader_program = shader->shader.handle; |
| 982 | state.Apply(); | 1007 | state.Apply(); |
| 983 | 1008 | ||
| 984 | // Set the texture samplers to correspond to different texture units | 1009 | // Set the texture samplers to correspond to different texture units |
| 985 | GLuint uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[0]"); | 1010 | GLuint uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[0]"); |
| 986 | if (uniform_tex != -1) { glUniform1i(uniform_tex, 0); } | 1011 | if (uniform_tex != -1) { |
| 1012 | glUniform1i(uniform_tex, 0); | ||
| 1013 | } | ||
| 987 | uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[1]"); | 1014 | uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[1]"); |
| 988 | if (uniform_tex != -1) { glUniform1i(uniform_tex, 1); } | 1015 | if (uniform_tex != -1) { |
| 1016 | glUniform1i(uniform_tex, 1); | ||
| 1017 | } | ||
| 989 | uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[2]"); | 1018 | uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[2]"); |
| 990 | if (uniform_tex != -1) { glUniform1i(uniform_tex, 2); } | 1019 | if (uniform_tex != -1) { |
| 1020 | glUniform1i(uniform_tex, 2); | ||
| 1021 | } | ||
| 991 | 1022 | ||
| 992 | // Set the texture samplers to correspond to different lookup table texture units | 1023 | // Set the texture samplers to correspond to different lookup table texture units |
| 993 | GLuint uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[0]"); | 1024 | GLuint uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[0]"); |
| 994 | if (uniform_lut != -1) { glUniform1i(uniform_lut, 3); } | 1025 | if (uniform_lut != -1) { |
| 1026 | glUniform1i(uniform_lut, 3); | ||
| 1027 | } | ||
| 995 | uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[1]"); | 1028 | uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[1]"); |
| 996 | if (uniform_lut != -1) { glUniform1i(uniform_lut, 4); } | 1029 | if (uniform_lut != -1) { |
| 1030 | glUniform1i(uniform_lut, 4); | ||
| 1031 | } | ||
| 997 | uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[2]"); | 1032 | uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[2]"); |
| 998 | if (uniform_lut != -1) { glUniform1i(uniform_lut, 5); } | 1033 | if (uniform_lut != -1) { |
| 1034 | glUniform1i(uniform_lut, 5); | ||
| 1035 | } | ||
| 999 | uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[3]"); | 1036 | uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[3]"); |
| 1000 | if (uniform_lut != -1) { glUniform1i(uniform_lut, 6); } | 1037 | if (uniform_lut != -1) { |
| 1038 | glUniform1i(uniform_lut, 6); | ||
| 1039 | } | ||
| 1001 | uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[4]"); | 1040 | uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[4]"); |
| 1002 | if (uniform_lut != -1) { glUniform1i(uniform_lut, 7); } | 1041 | if (uniform_lut != -1) { |
| 1042 | glUniform1i(uniform_lut, 7); | ||
| 1043 | } | ||
| 1003 | uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[5]"); | 1044 | uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[5]"); |
| 1004 | if (uniform_lut != -1) { glUniform1i(uniform_lut, 8); } | 1045 | if (uniform_lut != -1) { |
| 1046 | glUniform1i(uniform_lut, 8); | ||
| 1047 | } | ||
| 1005 | 1048 | ||
| 1006 | GLuint uniform_fog_lut = glGetUniformLocation(shader->shader.handle, "fog_lut"); | 1049 | GLuint uniform_fog_lut = glGetUniformLocation(shader->shader.handle, "fog_lut"); |
| 1007 | if (uniform_fog_lut != -1) { glUniform1i(uniform_fog_lut, 9); } | 1050 | if (uniform_fog_lut != -1) { |
| 1051 | glUniform1i(uniform_fog_lut, 9); | ||
| 1052 | } | ||
| 1008 | 1053 | ||
| 1009 | current_shader = shader_cache.emplace(config, std::move(shader)).first->second.get(); | 1054 | current_shader = shader_cache.emplace(config, std::move(shader)).first->second.get(); |
| 1010 | 1055 | ||
| 1011 | unsigned int block_index = glGetUniformBlockIndex(current_shader->shader.handle, "shader_data"); | 1056 | unsigned int block_index = |
| 1057 | glGetUniformBlockIndex(current_shader->shader.handle, "shader_data"); | ||
| 1012 | GLint block_size; | 1058 | GLint block_size; |
| 1013 | glGetActiveUniformBlockiv(current_shader->shader.handle, block_index, GL_UNIFORM_BLOCK_DATA_SIZE, &block_size); | 1059 | glGetActiveUniformBlockiv(current_shader->shader.handle, block_index, |
| 1060 | GL_UNIFORM_BLOCK_DATA_SIZE, &block_size); | ||
| 1014 | ASSERT_MSG(block_size == sizeof(UniformData), "Uniform block size did not match!"); | 1061 | ASSERT_MSG(block_size == sizeof(UniformData), "Uniform block size did not match!"); |
| 1015 | glUniformBlockBinding(current_shader->shader.handle, block_index, 0); | 1062 | glUniformBlockBinding(current_shader->shader.handle, block_index, 0); |
| 1016 | 1063 | ||
| @@ -1073,7 +1120,8 @@ void RasterizerOpenGL::SyncDepthScale() { | |||
| 1073 | } | 1120 | } |
| 1074 | 1121 | ||
| 1075 | void RasterizerOpenGL::SyncDepthOffset() { | 1122 | void RasterizerOpenGL::SyncDepthOffset() { |
| 1076 | float depth_offset = Pica::float24::FromRaw(Pica::g_state.regs.viewport_depth_near_plane).ToFloat32(); | 1123 | float depth_offset = |
| 1124 | Pica::float24::FromRaw(Pica::g_state.regs.viewport_depth_near_plane).ToFloat32(); | ||
| 1077 | if (depth_offset != uniform_block_data.data.depth_offset) { | 1125 | if (depth_offset != uniform_block_data.data.depth_offset) { |
| 1078 | uniform_block_data.data.depth_offset = depth_offset; | 1126 | uniform_block_data.data.depth_offset = depth_offset; |
| 1079 | uniform_block_data.dirty = true; | 1127 | uniform_block_data.dirty = true; |
| @@ -1086,10 +1134,14 @@ void RasterizerOpenGL::SyncBlendEnabled() { | |||
| 1086 | 1134 | ||
| 1087 | void RasterizerOpenGL::SyncBlendFuncs() { | 1135 | void RasterizerOpenGL::SyncBlendFuncs() { |
| 1088 | const auto& regs = Pica::g_state.regs; | 1136 | const auto& regs = Pica::g_state.regs; |
| 1089 | state.blend.rgb_equation = PicaToGL::BlendEquation(regs.output_merger.alpha_blending.blend_equation_rgb); | 1137 | state.blend.rgb_equation = |
| 1090 | state.blend.a_equation = PicaToGL::BlendEquation(regs.output_merger.alpha_blending.blend_equation_a); | 1138 | PicaToGL::BlendEquation(regs.output_merger.alpha_blending.blend_equation_rgb); |
| 1091 | state.blend.src_rgb_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_rgb); | 1139 | state.blend.a_equation = |
| 1092 | state.blend.dst_rgb_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_rgb); | 1140 | PicaToGL::BlendEquation(regs.output_merger.alpha_blending.blend_equation_a); |
| 1141 | state.blend.src_rgb_func = | ||
| 1142 | PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_rgb); | ||
| 1143 | state.blend.dst_rgb_func = | ||
| 1144 | PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_rgb); | ||
| 1093 | state.blend.src_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_a); | 1145 | state.blend.src_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_a); |
| 1094 | state.blend.dst_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_a); | 1146 | state.blend.dst_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_a); |
| 1095 | } | 1147 | } |
| @@ -1104,25 +1156,23 @@ void RasterizerOpenGL::SyncBlendColor() { | |||
| 1104 | 1156 | ||
| 1105 | void RasterizerOpenGL::SyncFogColor() { | 1157 | void RasterizerOpenGL::SyncFogColor() { |
| 1106 | const auto& regs = Pica::g_state.regs; | 1158 | const auto& regs = Pica::g_state.regs; |
| 1107 | uniform_block_data.data.fog_color = { | 1159 | uniform_block_data.data.fog_color = {regs.fog_color.r.Value() / 255.0f, |
| 1108 | regs.fog_color.r.Value() / 255.0f, | 1160 | regs.fog_color.g.Value() / 255.0f, |
| 1109 | regs.fog_color.g.Value() / 255.0f, | 1161 | regs.fog_color.b.Value() / 255.0f}; |
| 1110 | regs.fog_color.b.Value() / 255.0f | ||
| 1111 | }; | ||
| 1112 | uniform_block_data.dirty = true; | 1162 | uniform_block_data.dirty = true; |
| 1113 | } | 1163 | } |
| 1114 | 1164 | ||
| 1115 | void RasterizerOpenGL::SyncFogLUT() { | 1165 | void RasterizerOpenGL::SyncFogLUT() { |
| 1116 | std::array<GLuint, 128> new_data; | 1166 | std::array<GLuint, 128> new_data; |
| 1117 | 1167 | ||
| 1118 | std::transform(Pica::g_state.fog.lut.begin(), Pica::g_state.fog.lut.end(), new_data.begin(), [](const auto& entry) { | 1168 | std::transform(Pica::g_state.fog.lut.begin(), Pica::g_state.fog.lut.end(), new_data.begin(), |
| 1119 | return entry.raw; | 1169 | [](const auto& entry) { return entry.raw; }); |
| 1120 | }); | ||
| 1121 | 1170 | ||
| 1122 | if (new_data != fog_lut_data) { | 1171 | if (new_data != fog_lut_data) { |
| 1123 | fog_lut_data = new_data; | 1172 | fog_lut_data = new_data; |
| 1124 | glActiveTexture(GL_TEXTURE9); | 1173 | glActiveTexture(GL_TEXTURE9); |
| 1125 | glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 128, GL_RED_INTEGER, GL_UNSIGNED_INT, fog_lut_data.data()); | 1174 | glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 128, GL_RED_INTEGER, GL_UNSIGNED_INT, |
| 1175 | fog_lut_data.data()); | ||
| 1126 | } | 1176 | } |
| 1127 | } | 1177 | } |
| 1128 | 1178 | ||
| @@ -1154,34 +1204,40 @@ void RasterizerOpenGL::SyncColorWriteMask() { | |||
| 1154 | void RasterizerOpenGL::SyncStencilWriteMask() { | 1204 | void RasterizerOpenGL::SyncStencilWriteMask() { |
| 1155 | const auto& regs = Pica::g_state.regs; | 1205 | const auto& regs = Pica::g_state.regs; |
| 1156 | state.stencil.write_mask = (regs.framebuffer.allow_depth_stencil_write != 0) | 1206 | state.stencil.write_mask = (regs.framebuffer.allow_depth_stencil_write != 0) |
| 1157 | ? static_cast<GLuint>(regs.output_merger.stencil_test.write_mask) | 1207 | ? static_cast<GLuint>(regs.output_merger.stencil_test.write_mask) |
| 1158 | : 0; | 1208 | : 0; |
| 1159 | } | 1209 | } |
| 1160 | 1210 | ||
| 1161 | void RasterizerOpenGL::SyncDepthWriteMask() { | 1211 | void RasterizerOpenGL::SyncDepthWriteMask() { |
| 1162 | const auto& regs = Pica::g_state.regs; | 1212 | const auto& regs = Pica::g_state.regs; |
| 1163 | state.depth.write_mask = (regs.framebuffer.allow_depth_stencil_write != 0 && regs.output_merger.depth_write_enable) | 1213 | state.depth.write_mask = |
| 1164 | ? GL_TRUE | 1214 | (regs.framebuffer.allow_depth_stencil_write != 0 && regs.output_merger.depth_write_enable) |
| 1165 | : GL_FALSE; | 1215 | ? GL_TRUE |
| 1216 | : GL_FALSE; | ||
| 1166 | } | 1217 | } |
| 1167 | 1218 | ||
| 1168 | void RasterizerOpenGL::SyncStencilTest() { | 1219 | void RasterizerOpenGL::SyncStencilTest() { |
| 1169 | const auto& regs = Pica::g_state.regs; | 1220 | const auto& regs = Pica::g_state.regs; |
| 1170 | state.stencil.test_enabled = regs.output_merger.stencil_test.enable && regs.framebuffer.depth_format == Pica::Regs::DepthFormat::D24S8; | 1221 | state.stencil.test_enabled = regs.output_merger.stencil_test.enable && |
| 1222 | regs.framebuffer.depth_format == Pica::Regs::DepthFormat::D24S8; | ||
| 1171 | state.stencil.test_func = PicaToGL::CompareFunc(regs.output_merger.stencil_test.func); | 1223 | state.stencil.test_func = PicaToGL::CompareFunc(regs.output_merger.stencil_test.func); |
| 1172 | state.stencil.test_ref = regs.output_merger.stencil_test.reference_value; | 1224 | state.stencil.test_ref = regs.output_merger.stencil_test.reference_value; |
| 1173 | state.stencil.test_mask = regs.output_merger.stencil_test.input_mask; | 1225 | state.stencil.test_mask = regs.output_merger.stencil_test.input_mask; |
| 1174 | state.stencil.action_stencil_fail = PicaToGL::StencilOp(regs.output_merger.stencil_test.action_stencil_fail); | 1226 | state.stencil.action_stencil_fail = |
| 1175 | state.stencil.action_depth_fail = PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_fail); | 1227 | PicaToGL::StencilOp(regs.output_merger.stencil_test.action_stencil_fail); |
| 1176 | state.stencil.action_depth_pass = PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_pass); | 1228 | state.stencil.action_depth_fail = |
| 1229 | PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_fail); | ||
| 1230 | state.stencil.action_depth_pass = | ||
| 1231 | PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_pass); | ||
| 1177 | } | 1232 | } |
| 1178 | 1233 | ||
| 1179 | void RasterizerOpenGL::SyncDepthTest() { | 1234 | void RasterizerOpenGL::SyncDepthTest() { |
| 1180 | const auto& regs = Pica::g_state.regs; | 1235 | const auto& regs = Pica::g_state.regs; |
| 1181 | state.depth.test_enabled = regs.output_merger.depth_test_enable == 1 || | 1236 | state.depth.test_enabled = |
| 1182 | regs.output_merger.depth_write_enable == 1; | 1237 | regs.output_merger.depth_test_enable == 1 || regs.output_merger.depth_write_enable == 1; |
| 1183 | state.depth.test_func = regs.output_merger.depth_test_enable == 1 ? | 1238 | state.depth.test_func = regs.output_merger.depth_test_enable == 1 |
| 1184 | PicaToGL::CompareFunc(regs.output_merger.depth_test_func) : GL_ALWAYS; | 1239 | ? PicaToGL::CompareFunc(regs.output_merger.depth_test_func) |
| 1240 | : GL_ALWAYS; | ||
| 1185 | } | 1241 | } |
| 1186 | 1242 | ||
| 1187 | void RasterizerOpenGL::SyncScissorTest() { | 1243 | void RasterizerOpenGL::SyncScissorTest() { |
| @@ -1208,7 +1264,8 @@ void RasterizerOpenGL::SyncCombinerColor() { | |||
| 1208 | } | 1264 | } |
| 1209 | } | 1265 | } |
| 1210 | 1266 | ||
| 1211 | void RasterizerOpenGL::SyncTevConstColor(int stage_index, const Pica::Regs::TevStageConfig& tev_stage) { | 1267 | void RasterizerOpenGL::SyncTevConstColor(int stage_index, |
| 1268 | const Pica::Regs::TevStageConfig& tev_stage) { | ||
| 1212 | auto const_color = PicaToGL::ColorRGBA8(tev_stage.const_color); | 1269 | auto const_color = PicaToGL::ColorRGBA8(tev_stage.const_color); |
| 1213 | if (const_color != uniform_block_data.data.const_color[stage_index]) { | 1270 | if (const_color != uniform_block_data.data.const_color[stage_index]) { |
| 1214 | uniform_block_data.data.const_color[stage_index] = const_color; | 1271 | uniform_block_data.data.const_color[stage_index] = const_color; |
| @@ -1237,7 +1294,8 @@ void RasterizerOpenGL::SyncLightingLUT(unsigned lut_index) { | |||
| 1237 | if (new_data != lighting_lut_data[lut_index]) { | 1294 | if (new_data != lighting_lut_data[lut_index]) { |
| 1238 | lighting_lut_data[lut_index] = new_data; | 1295 | lighting_lut_data[lut_index] = new_data; |
| 1239 | glActiveTexture(GL_TEXTURE3 + lut_index); | 1296 | glActiveTexture(GL_TEXTURE3 + lut_index); |
| 1240 | glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 256, GL_RGBA, GL_FLOAT, lighting_lut_data[lut_index].data()); | 1297 | glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 256, GL_RGBA, GL_FLOAT, |
| 1298 | lighting_lut_data[lut_index].data()); | ||
| 1241 | } | 1299 | } |
| 1242 | } | 1300 | } |
| 1243 | 1301 | ||
| @@ -1277,7 +1335,7 @@ void RasterizerOpenGL::SyncLightPosition(int light_index) { | |||
| 1277 | GLvec3 position = { | 1335 | GLvec3 position = { |
| 1278 | Pica::float16::FromRaw(Pica::g_state.regs.lighting.light[light_index].x).ToFloat32(), | 1336 | Pica::float16::FromRaw(Pica::g_state.regs.lighting.light[light_index].x).ToFloat32(), |
| 1279 | Pica::float16::FromRaw(Pica::g_state.regs.lighting.light[light_index].y).ToFloat32(), | 1337 | Pica::float16::FromRaw(Pica::g_state.regs.lighting.light[light_index].y).ToFloat32(), |
| 1280 | Pica::float16::FromRaw(Pica::g_state.regs.lighting.light[light_index].z).ToFloat32() }; | 1338 | Pica::float16::FromRaw(Pica::g_state.regs.lighting.light[light_index].z).ToFloat32()}; |
| 1281 | 1339 | ||
| 1282 | if (position != uniform_block_data.data.light_src[light_index].position) { | 1340 | if (position != uniform_block_data.data.light_src[light_index].position) { |
| 1283 | uniform_block_data.data.light_src[light_index].position = position; | 1341 | uniform_block_data.data.light_src[light_index].position = position; |
| @@ -1286,7 +1344,9 @@ void RasterizerOpenGL::SyncLightPosition(int light_index) { | |||
| 1286 | } | 1344 | } |
| 1287 | 1345 | ||
| 1288 | void RasterizerOpenGL::SyncLightDistanceAttenuationBias(int light_index) { | 1346 | void RasterizerOpenGL::SyncLightDistanceAttenuationBias(int light_index) { |
| 1289 | GLfloat dist_atten_bias = Pica::float20::FromRaw(Pica::g_state.regs.lighting.light[light_index].dist_atten_bias).ToFloat32(); | 1347 | GLfloat dist_atten_bias = |
| 1348 | Pica::float20::FromRaw(Pica::g_state.regs.lighting.light[light_index].dist_atten_bias) | ||
| 1349 | .ToFloat32(); | ||
| 1290 | 1350 | ||
| 1291 | if (dist_atten_bias != uniform_block_data.data.light_src[light_index].dist_atten_bias) { | 1351 | if (dist_atten_bias != uniform_block_data.data.light_src[light_index].dist_atten_bias) { |
| 1292 | uniform_block_data.data.light_src[light_index].dist_atten_bias = dist_atten_bias; | 1352 | uniform_block_data.data.light_src[light_index].dist_atten_bias = dist_atten_bias; |
| @@ -1295,7 +1355,9 @@ void RasterizerOpenGL::SyncLightDistanceAttenuationBias(int light_index) { | |||
| 1295 | } | 1355 | } |
| 1296 | 1356 | ||
| 1297 | void RasterizerOpenGL::SyncLightDistanceAttenuationScale(int light_index) { | 1357 | void RasterizerOpenGL::SyncLightDistanceAttenuationScale(int light_index) { |
| 1298 | GLfloat dist_atten_scale = Pica::float20::FromRaw(Pica::g_state.regs.lighting.light[light_index].dist_atten_scale).ToFloat32(); | 1358 | GLfloat dist_atten_scale = |
| 1359 | Pica::float20::FromRaw(Pica::g_state.regs.lighting.light[light_index].dist_atten_scale) | ||
| 1360 | .ToFloat32(); | ||
| 1299 | 1361 | ||
| 1300 | if (dist_atten_scale != uniform_block_data.data.light_src[light_index].dist_atten_scale) { | 1362 | if (dist_atten_scale != uniform_block_data.data.light_src[light_index].dist_atten_scale) { |
| 1301 | uniform_block_data.data.light_src[light_index].dist_atten_scale = dist_atten_scale; | 1363 | 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 @@ | |||
| 8 | #include <cstddef> | 8 | #include <cstddef> |
| 9 | #include <cstring> | 9 | #include <cstring> |
| 10 | #include <memory> | 10 | #include <memory> |
| 11 | #include <vector> | ||
| 12 | #include <unordered_map> | 11 | #include <unordered_map> |
| 12 | #include <vector> | ||
| 13 | 13 | ||
| 14 | #include <glad/glad.h> | 14 | #include <glad/glad.h> |
| 15 | 15 | ||
| @@ -40,10 +40,13 @@ struct ScreenInfo; | |||
| 40 | * Pica state is not being captured in the shader cache key, thereby resulting in (what should be) | 40 | * Pica state is not being captured in the shader cache key, thereby resulting in (what should be) |
| 41 | * two separate shaders sharing the same key. | 41 | * two separate shaders sharing the same key. |
| 42 | * | 42 | * |
| 43 | * We use a union because "implicitly-defined copy/move constructor for a union X copies the object representation of X." | 43 | * We use a union because "implicitly-defined copy/move constructor for a union X copies the object |
| 44 | * and "implicitly-defined copy assignment operator for a union X copies the object representation (3.9) of X." | 44 | * representation of X." |
| 45 | * and "implicitly-defined copy assignment operator for a union X copies the object representation | ||
| 46 | * (3.9) of X." | ||
| 45 | * = Bytewise copy instead of memberwise copy. | 47 | * = Bytewise copy instead of memberwise copy. |
| 46 | * This is important because the padding bytes are included in the hash and comparison between objects. | 48 | * This is important because the padding bytes are included in the hash and comparison between |
| 49 | * objects. | ||
| 47 | */ | 50 | */ |
| 48 | union PicaShaderConfig { | 51 | union PicaShaderConfig { |
| 49 | 52 | ||
| @@ -60,8 +63,9 @@ union PicaShaderConfig { | |||
| 60 | 63 | ||
| 61 | state.depthmap_enable = regs.depthmap_enable; | 64 | state.depthmap_enable = regs.depthmap_enable; |
| 62 | 65 | ||
| 63 | state.alpha_test_func = regs.output_merger.alpha_test.enable ? | 66 | state.alpha_test_func = regs.output_merger.alpha_test.enable |
| 64 | regs.output_merger.alpha_test.func.Value() : Pica::Regs::CompareFunc::Always; | 67 | ? regs.output_merger.alpha_test.func.Value() |
| 68 | : Pica::Regs::CompareFunc::Always; | ||
| 65 | 69 | ||
| 66 | state.texture0_type = regs.texture0.type; | 70 | state.texture0_type = regs.texture0.type; |
| 67 | 71 | ||
| @@ -81,9 +85,8 @@ union PicaShaderConfig { | |||
| 81 | state.fog_mode = regs.fog_mode; | 85 | state.fog_mode = regs.fog_mode; |
| 82 | state.fog_flip = regs.fog_flip; | 86 | state.fog_flip = regs.fog_flip; |
| 83 | 87 | ||
| 84 | state.combiner_buffer_input = | 88 | state.combiner_buffer_input = regs.tev_combiner_buffer_input.update_mask_rgb.Value() | |
| 85 | regs.tev_combiner_buffer_input.update_mask_rgb.Value() | | 89 | regs.tev_combiner_buffer_input.update_mask_a.Value() << 4; |
| 86 | regs.tev_combiner_buffer_input.update_mask_a.Value() << 4; | ||
| 87 | 90 | ||
| 88 | // Fragment lighting | 91 | // Fragment lighting |
| 89 | 92 | ||
| @@ -95,8 +98,10 @@ union PicaShaderConfig { | |||
| 95 | const auto& light = regs.lighting.light[num]; | 98 | const auto& light = regs.lighting.light[num]; |
| 96 | state.lighting.light[light_index].num = num; | 99 | state.lighting.light[light_index].num = num; |
| 97 | state.lighting.light[light_index].directional = light.config.directional != 0; | 100 | state.lighting.light[light_index].directional = light.config.directional != 0; |
| 98 | state.lighting.light[light_index].two_sided_diffuse = light.config.two_sided_diffuse != 0; | 101 | state.lighting.light[light_index].two_sided_diffuse = |
| 99 | state.lighting.light[light_index].dist_atten_enable = !regs.lighting.IsDistAttenDisabled(num); | 102 | light.config.two_sided_diffuse != 0; |
| 103 | state.lighting.light[light_index].dist_atten_enable = | ||
| 104 | !regs.lighting.IsDistAttenDisabled(num); | ||
| 100 | } | 105 | } |
| 101 | 106 | ||
| 102 | state.lighting.lut_d0.enable = regs.lighting.config1.disable_lut_d0 == 0; | 107 | state.lighting.lut_d0.enable = regs.lighting.config1.disable_lut_d0 == 0; |
| @@ -147,7 +152,7 @@ union PicaShaderConfig { | |||
| 147 | return (stage_index < 4) && ((state.combiner_buffer_input >> 4) & (1 << stage_index)); | 152 | return (stage_index < 4) && ((state.combiner_buffer_input >> 4) & (1 << stage_index)); |
| 148 | } | 153 | } |
| 149 | 154 | ||
| 150 | bool operator ==(const PicaShaderConfig& o) const { | 155 | bool operator==(const PicaShaderConfig& o) const { |
| 151 | return std::memcmp(&state, &o.state, sizeof(PicaShaderConfig::State)) == 0; | 156 | return std::memcmp(&state, &o.state, sizeof(PicaShaderConfig::State)) == 0; |
| 152 | }; | 157 | }; |
| 153 | 158 | ||
| @@ -212,7 +217,8 @@ union PicaShaderConfig { | |||
| 212 | } state; | 217 | } state; |
| 213 | }; | 218 | }; |
| 214 | #if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER) | 219 | #if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER) |
| 215 | static_assert(std::is_trivially_copyable<PicaShaderConfig::State>::value, "PicaShaderConfig::State must be trivially copyable"); | 220 | static_assert(std::is_trivially_copyable<PicaShaderConfig::State>::value, |
| 221 | "PicaShaderConfig::State must be trivially copyable"); | ||
| 216 | #endif | 222 | #endif |
| 217 | 223 | ||
| 218 | namespace std { | 224 | namespace std { |
| @@ -228,12 +234,10 @@ struct hash<PicaShaderConfig> { | |||
| 228 | 234 | ||
| 229 | class RasterizerOpenGL : public VideoCore::RasterizerInterface { | 235 | class RasterizerOpenGL : public VideoCore::RasterizerInterface { |
| 230 | public: | 236 | public: |
| 231 | |||
| 232 | RasterizerOpenGL(); | 237 | RasterizerOpenGL(); |
| 233 | ~RasterizerOpenGL() override; | 238 | ~RasterizerOpenGL() override; |
| 234 | 239 | ||
| 235 | void AddTriangle(const Pica::Shader::OutputVertex& v0, | 240 | void AddTriangle(const Pica::Shader::OutputVertex& v0, const Pica::Shader::OutputVertex& v1, |
| 236 | const Pica::Shader::OutputVertex& v1, | ||
| 237 | const Pica::Shader::OutputVertex& v2) override; | 241 | const Pica::Shader::OutputVertex& v2) override; |
| 238 | void DrawTriangles() override; | 242 | void DrawTriangles() override; |
| 239 | void NotifyPicaRegisterChanged(u32 id) override; | 243 | void NotifyPicaRegisterChanged(u32 id) override; |
| @@ -242,7 +246,8 @@ public: | |||
| 242 | void FlushAndInvalidateRegion(PAddr addr, u32 size) override; | 246 | void FlushAndInvalidateRegion(PAddr addr, u32 size) override; |
| 243 | bool AccelerateDisplayTransfer(const GPU::Regs::DisplayTransferConfig& config) override; | 247 | bool AccelerateDisplayTransfer(const GPU::Regs::DisplayTransferConfig& config) override; |
| 244 | bool AccelerateFill(const GPU::Regs::MemoryFillConfig& config) override; | 248 | bool AccelerateFill(const GPU::Regs::MemoryFillConfig& config) override; |
| 245 | bool AccelerateDisplay(const GPU::Regs::FramebufferConfig& config, PAddr framebuffer_addr, u32 pixel_stride, ScreenInfo& screen_info) override; | 249 | bool AccelerateDisplay(const GPU::Regs::FramebufferConfig& config, PAddr framebuffer_addr, |
| 250 | u32 pixel_stride, ScreenInfo& screen_info) override; | ||
| 246 | 251 | ||
| 247 | /// OpenGL shader generated for a given Pica register state | 252 | /// OpenGL shader generated for a given Pica register state |
| 248 | struct PicaShader { | 253 | struct PicaShader { |
| @@ -251,13 +256,13 @@ public: | |||
| 251 | }; | 256 | }; |
| 252 | 257 | ||
| 253 | private: | 258 | private: |
| 254 | |||
| 255 | struct SamplerInfo { | 259 | struct SamplerInfo { |
| 256 | using TextureConfig = Pica::Regs::TextureConfig; | 260 | using TextureConfig = Pica::Regs::TextureConfig; |
| 257 | 261 | ||
| 258 | OGLSampler sampler; | 262 | OGLSampler sampler; |
| 259 | 263 | ||
| 260 | /// Creates the sampler object, initializing its state so that it's in sync with the SamplerInfo struct. | 264 | /// Creates the sampler object, initializing its state so that it's in sync with the |
| 265 | /// SamplerInfo struct. | ||
| 261 | void Create(); | 266 | void Create(); |
| 262 | /// Syncs the sampler object with the config, updating any necessary state. | 267 | /// Syncs the sampler object with the config, updating any necessary state. |
| 263 | void SyncWithConfig(const TextureConfig& config); | 268 | void SyncWithConfig(const TextureConfig& config); |
| @@ -343,8 +348,11 @@ private: | |||
| 343 | alignas(16) GLvec4 tev_combiner_buffer_color; | 348 | alignas(16) GLvec4 tev_combiner_buffer_color; |
| 344 | }; | 349 | }; |
| 345 | 350 | ||
| 346 | static_assert(sizeof(UniformData) == 0x3C0, "The size of the UniformData structure has changed, update the structure in the shader"); | 351 | static_assert( |
| 347 | static_assert(sizeof(UniformData) < 16384, "UniformData structure must be less than 16kb as per the OpenGL spec"); | 352 | sizeof(UniformData) == 0x3C0, |
| 353 | "The size of the UniformData structure has changed, update the structure in the shader"); | ||
| 354 | static_assert(sizeof(UniformData) < 16384, | ||
| 355 | "UniformData structure must be less than 16kb as per the OpenGL spec"); | ||
| 348 | 356 | ||
| 349 | /// Sets the OpenGL shader in accordance with the current PICA register state | 357 | /// Sets the OpenGL shader in accordance with the current PICA register state |
| 350 | void SetShader(); | 358 | 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 { | |||
| 35 | }; | 35 | }; |
| 36 | 36 | ||
| 37 | static const std::array<FormatTuple, 5> fb_format_tuples = {{ | 37 | static const std::array<FormatTuple, 5> fb_format_tuples = {{ |
| 38 | { GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8 }, // RGBA8 | 38 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8}, // RGBA8 |
| 39 | { GL_RGB8, GL_BGR, GL_UNSIGNED_BYTE }, // RGB8 | 39 | {GL_RGB8, GL_BGR, GL_UNSIGNED_BYTE}, // RGB8 |
| 40 | { GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 }, // RGB5A1 | 40 | {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1}, // RGB5A1 |
| 41 | { GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 }, // RGB565 | 41 | {GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}, // RGB565 |
| 42 | { GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 }, // RGBA4 | 42 | {GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4}, // RGBA4 |
| 43 | }}; | 43 | }}; |
| 44 | 44 | ||
| 45 | static const std::array<FormatTuple, 4> depth_format_tuples = {{ | 45 | static const std::array<FormatTuple, 4> depth_format_tuples = {{ |
| 46 | { GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT }, // D16 | 46 | {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}, // D16 |
| 47 | {}, | 47 | {}, |
| 48 | { GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT }, // D24 | 48 | {GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT}, // D24 |
| 49 | { GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8 }, // D24S8 | 49 | {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // D24S8 |
| 50 | }}; | 50 | }}; |
| 51 | 51 | ||
| 52 | RasterizerCacheOpenGL::RasterizerCacheOpenGL() { | 52 | RasterizerCacheOpenGL::RasterizerCacheOpenGL() { |
| @@ -58,7 +58,9 @@ RasterizerCacheOpenGL::~RasterizerCacheOpenGL() { | |||
| 58 | FlushAll(); | 58 | FlushAll(); |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | 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) { | 61 | static void MortonCopyPixels(CachedSurface::PixelFormat pixel_format, u32 width, u32 height, |
| 62 | u32 bytes_per_pixel, u32 gl_bytes_per_pixel, u8* morton_data, | ||
| 63 | u8* gl_data, bool morton_to_gl) { | ||
| 62 | using PixelFormat = CachedSurface::PixelFormat; | 64 | using PixelFormat = CachedSurface::PixelFormat; |
| 63 | 65 | ||
| 64 | u8* data_ptrs[2]; | 66 | u8* data_ptrs[2]; |
| @@ -72,7 +74,8 @@ static void MortonCopyPixels(CachedSurface::PixelFormat pixel_format, u32 width, | |||
| 72 | for (unsigned y = 0; y < height; ++y) { | 74 | for (unsigned y = 0; y < height; ++y) { |
| 73 | for (unsigned x = 0; x < width; ++x) { | 75 | for (unsigned x = 0; x < width; ++x) { |
| 74 | const u32 coarse_y = y & ~7; | 76 | const u32 coarse_y = y & ~7; |
| 75 | u32 morton_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * width * bytes_per_pixel; | 77 | u32 morton_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + |
| 78 | coarse_y * width * bytes_per_pixel; | ||
| 76 | u32 gl_pixel_index = (x + (height - 1 - y) * width) * gl_bytes_per_pixel; | 79 | u32 gl_pixel_index = (x + (height - 1 - y) * width) * gl_bytes_per_pixel; |
| 77 | 80 | ||
| 78 | data_ptrs[morton_to_gl] = morton_data + morton_offset; | 81 | data_ptrs[morton_to_gl] = morton_data + morton_offset; |
| @@ -81,7 +84,8 @@ static void MortonCopyPixels(CachedSurface::PixelFormat pixel_format, u32 width, | |||
| 81 | // Swap depth and stencil value ordering since 3DS does not match OpenGL | 84 | // Swap depth and stencil value ordering since 3DS does not match OpenGL |
| 82 | u32 depth_stencil; | 85 | u32 depth_stencil; |
| 83 | memcpy(&depth_stencil, data_ptrs[1], sizeof(u32)); | 86 | memcpy(&depth_stencil, data_ptrs[1], sizeof(u32)); |
| 84 | depth_stencil = (depth_stencil << depth_stencil_shifts[0]) | (depth_stencil >> depth_stencil_shifts[1]); | 87 | depth_stencil = (depth_stencil << depth_stencil_shifts[0]) | |
| 88 | (depth_stencil >> depth_stencil_shifts[1]); | ||
| 85 | 89 | ||
| 86 | memcpy(data_ptrs[0], &depth_stencil, sizeof(u32)); | 90 | memcpy(data_ptrs[0], &depth_stencil, sizeof(u32)); |
| 87 | } | 91 | } |
| @@ -90,7 +94,8 @@ static void MortonCopyPixels(CachedSurface::PixelFormat pixel_format, u32 width, | |||
| 90 | for (unsigned y = 0; y < height; ++y) { | 94 | for (unsigned y = 0; y < height; ++y) { |
| 91 | for (unsigned x = 0; x < width; ++x) { | 95 | for (unsigned x = 0; x < width; ++x) { |
| 92 | const u32 coarse_y = y & ~7; | 96 | const u32 coarse_y = y & ~7; |
| 93 | u32 morton_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * width * bytes_per_pixel; | 97 | u32 morton_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + |
| 98 | coarse_y * width * bytes_per_pixel; | ||
| 94 | u32 gl_pixel_index = (x + (height - 1 - y) * width) * gl_bytes_per_pixel; | 99 | u32 gl_pixel_index = (x + (height - 1 - y) * width) * gl_bytes_per_pixel; |
| 95 | 100 | ||
| 96 | data_ptrs[morton_to_gl] = morton_data + morton_offset; | 101 | data_ptrs[morton_to_gl] = morton_data + morton_offset; |
| @@ -102,17 +107,21 @@ static void MortonCopyPixels(CachedSurface::PixelFormat pixel_format, u32 width, | |||
| 102 | } | 107 | } |
| 103 | } | 108 | } |
| 104 | 109 | ||
| 105 | bool RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex, CachedSurface::SurfaceType type, const MathUtil::Rectangle<int>& src_rect, const MathUtil::Rectangle<int>& dst_rect) { | 110 | bool RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex, |
| 111 | CachedSurface::SurfaceType type, | ||
| 112 | const MathUtil::Rectangle<int>& src_rect, | ||
| 113 | const MathUtil::Rectangle<int>& dst_rect) { | ||
| 106 | using SurfaceType = CachedSurface::SurfaceType; | 114 | using SurfaceType = CachedSurface::SurfaceType; |
| 107 | 115 | ||
| 108 | OpenGLState cur_state = OpenGLState::GetCurState(); | 116 | OpenGLState cur_state = OpenGLState::GetCurState(); |
| 109 | 117 | ||
| 110 | // Make sure textures aren't bound to texture units, since going to bind them to framebuffer components | 118 | // Make sure textures aren't bound to texture units, since going to bind them to framebuffer |
| 119 | // components | ||
| 111 | OpenGLState::ResetTexture(src_tex); | 120 | OpenGLState::ResetTexture(src_tex); |
| 112 | OpenGLState::ResetTexture(dst_tex); | 121 | OpenGLState::ResetTexture(dst_tex); |
| 113 | 122 | ||
| 114 | // Keep track of previous framebuffer bindings | 123 | // Keep track of previous framebuffer bindings |
| 115 | GLuint old_fbs[2] = { cur_state.draw.read_framebuffer, cur_state.draw.draw_framebuffer }; | 124 | GLuint old_fbs[2] = {cur_state.draw.read_framebuffer, cur_state.draw.draw_framebuffer}; |
| 116 | cur_state.draw.read_framebuffer = transfer_framebuffers[0].handle; | 125 | cur_state.draw.read_framebuffer = transfer_framebuffers[0].handle; |
| 117 | cur_state.draw.draw_framebuffer = transfer_framebuffers[1].handle; | 126 | cur_state.draw.draw_framebuffer = transfer_framebuffers[1].handle; |
| 118 | cur_state.Apply(); | 127 | cur_state.Apply(); |
| @@ -120,11 +129,15 @@ bool RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex, CachedS | |||
| 120 | u32 buffers = 0; | 129 | u32 buffers = 0; |
| 121 | 130 | ||
| 122 | if (type == SurfaceType::Color || type == SurfaceType::Texture) { | 131 | if (type == SurfaceType::Color || type == SurfaceType::Texture) { |
| 123 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, src_tex, 0); | 132 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, src_tex, |
| 124 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); | 133 | 0); |
| 134 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, | ||
| 135 | 0); | ||
| 125 | 136 | ||
| 126 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dst_tex, 0); | 137 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dst_tex, |
| 127 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); | 138 | 0); |
| 139 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, | ||
| 140 | 0); | ||
| 128 | 141 | ||
| 129 | buffers = GL_COLOR_BUFFER_BIT; | 142 | buffers = GL_COLOR_BUFFER_BIT; |
| 130 | } else if (type == SurfaceType::Depth) { | 143 | } else if (type == SurfaceType::Depth) { |
| @@ -139,10 +152,12 @@ bool RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex, CachedS | |||
| 139 | buffers = GL_DEPTH_BUFFER_BIT; | 152 | buffers = GL_DEPTH_BUFFER_BIT; |
| 140 | } else if (type == SurfaceType::DepthStencil) { | 153 | } else if (type == SurfaceType::DepthStencil) { |
| 141 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); | 154 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); |
| 142 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, src_tex, 0); | 155 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, |
| 156 | src_tex, 0); | ||
| 143 | 157 | ||
| 144 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); | 158 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); |
| 145 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, dst_tex, 0); | 159 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, |
| 160 | dst_tex, 0); | ||
| 146 | 161 | ||
| 147 | buffers = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; | 162 | buffers = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; |
| 148 | } | 163 | } |
| @@ -155,9 +170,9 @@ bool RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex, CachedS | |||
| 155 | return false; | 170 | return false; |
| 156 | } | 171 | } |
| 157 | 172 | ||
| 158 | glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom, | 173 | glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom, dst_rect.left, |
| 159 | dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, | 174 | dst_rect.top, dst_rect.right, dst_rect.bottom, buffers, |
| 160 | buffers, buffers == GL_COLOR_BUFFER_BIT ? GL_LINEAR : GL_NEAREST); | 175 | buffers == GL_COLOR_BUFFER_BIT ? GL_LINEAR : GL_NEAREST); |
| 161 | 176 | ||
| 162 | // Restore previous framebuffer bindings | 177 | // Restore previous framebuffer bindings |
| 163 | cur_state.draw.read_framebuffer = old_fbs[0]; | 178 | cur_state.draw.read_framebuffer = old_fbs[0]; |
| @@ -167,17 +182,24 @@ bool RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex, CachedS | |||
| 167 | return true; | 182 | return true; |
| 168 | } | 183 | } |
| 169 | 184 | ||
| 170 | bool RasterizerCacheOpenGL::TryBlitSurfaces(CachedSurface* src_surface, const MathUtil::Rectangle<int>& src_rect, CachedSurface* dst_surface, const MathUtil::Rectangle<int>& dst_rect) { | 185 | bool RasterizerCacheOpenGL::TryBlitSurfaces(CachedSurface* src_surface, |
| 186 | const MathUtil::Rectangle<int>& src_rect, | ||
| 187 | CachedSurface* dst_surface, | ||
| 188 | const MathUtil::Rectangle<int>& dst_rect) { | ||
| 171 | using SurfaceType = CachedSurface::SurfaceType; | 189 | using SurfaceType = CachedSurface::SurfaceType; |
| 172 | 190 | ||
| 173 | if (!CachedSurface::CheckFormatsBlittable(src_surface->pixel_format, dst_surface->pixel_format)) { | 191 | if (!CachedSurface::CheckFormatsBlittable(src_surface->pixel_format, |
| 192 | dst_surface->pixel_format)) { | ||
| 174 | return false; | 193 | return false; |
| 175 | } | 194 | } |
| 176 | 195 | ||
| 177 | return BlitTextures(src_surface->texture.handle, dst_surface->texture.handle, CachedSurface::GetFormatType(src_surface->pixel_format), src_rect, dst_rect); | 196 | return BlitTextures(src_surface->texture.handle, dst_surface->texture.handle, |
| 197 | CachedSurface::GetFormatType(src_surface->pixel_format), src_rect, | ||
| 198 | dst_rect); | ||
| 178 | } | 199 | } |
| 179 | 200 | ||
| 180 | static void AllocateSurfaceTexture(GLuint texture, CachedSurface::PixelFormat pixel_format, u32 width, u32 height) { | 201 | static void AllocateSurfaceTexture(GLuint texture, CachedSurface::PixelFormat pixel_format, |
| 202 | u32 width, u32 height) { | ||
| 181 | // Allocate an uninitialized texture of appropriate size and format for the surface | 203 | // Allocate an uninitialized texture of appropriate size and format for the surface |
| 182 | using SurfaceType = CachedSurface::SurfaceType; | 204 | using SurfaceType = CachedSurface::SurfaceType; |
| 183 | 205 | ||
| @@ -200,11 +222,11 @@ static void AllocateSurfaceTexture(GLuint texture, CachedSurface::PixelFormat pi | |||
| 200 | ASSERT(tuple_idx < depth_format_tuples.size()); | 222 | ASSERT(tuple_idx < depth_format_tuples.size()); |
| 201 | tuple = depth_format_tuples[tuple_idx]; | 223 | tuple = depth_format_tuples[tuple_idx]; |
| 202 | } else { | 224 | } else { |
| 203 | tuple = { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE }; | 225 | tuple = {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}; |
| 204 | } | 226 | } |
| 205 | 227 | ||
| 206 | glTexImage2D(GL_TEXTURE_2D, 0, tuple.internal_format, width, height, 0, | 228 | glTexImage2D(GL_TEXTURE_2D, 0, tuple.internal_format, width, height, 0, tuple.format, |
| 207 | tuple.format, tuple.type, nullptr); | 229 | tuple.type, nullptr); |
| 208 | 230 | ||
| 209 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); | 231 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); |
| 210 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 232 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| @@ -217,7 +239,8 @@ static void AllocateSurfaceTexture(GLuint texture, CachedSurface::PixelFormat pi | |||
| 217 | } | 239 | } |
| 218 | 240 | ||
| 219 | MICROPROFILE_DEFINE(OpenGL_SurfaceUpload, "OpenGL", "Surface Upload", MP_RGB(128, 64, 192)); | 241 | MICROPROFILE_DEFINE(OpenGL_SurfaceUpload, "OpenGL", "Surface Upload", MP_RGB(128, 64, 192)); |
| 220 | CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bool match_res_scale, bool load_if_create) { | 242 | CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bool match_res_scale, |
| 243 | bool load_if_create) { | ||
| 221 | using PixelFormat = CachedSurface::PixelFormat; | 244 | using PixelFormat = CachedSurface::PixelFormat; |
| 222 | using SurfaceType = CachedSurface::SurfaceType; | 245 | using SurfaceType = CachedSurface::SurfaceType; |
| 223 | 246 | ||
| @@ -225,29 +248,31 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo | |||
| 225 | return nullptr; | 248 | return nullptr; |
| 226 | } | 249 | } |
| 227 | 250 | ||
| 228 | u32 params_size = params.width * params.height * CachedSurface::GetFormatBpp(params.pixel_format) / 8; | 251 | u32 params_size = |
| 252 | params.width * params.height * CachedSurface::GetFormatBpp(params.pixel_format) / 8; | ||
| 229 | 253 | ||
| 230 | // Check for an exact match in existing surfaces | 254 | // Check for an exact match in existing surfaces |
| 231 | CachedSurface* best_exact_surface = nullptr; | 255 | CachedSurface* best_exact_surface = nullptr; |
| 232 | float exact_surface_goodness = -1.f; | 256 | float exact_surface_goodness = -1.f; |
| 233 | 257 | ||
| 234 | auto surface_interval = boost::icl::interval<PAddr>::right_open(params.addr, params.addr + params_size); | 258 | auto surface_interval = |
| 259 | boost::icl::interval<PAddr>::right_open(params.addr, params.addr + params_size); | ||
| 235 | auto range = surface_cache.equal_range(surface_interval); | 260 | auto range = surface_cache.equal_range(surface_interval); |
| 236 | for (auto it = range.first; it != range.second; ++it) { | 261 | for (auto it = range.first; it != range.second; ++it) { |
| 237 | for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2) { | 262 | for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2) { |
| 238 | CachedSurface* surface = it2->get(); | 263 | CachedSurface* surface = it2->get(); |
| 239 | 264 | ||
| 240 | // Check if the request matches the surface exactly | 265 | // Check if the request matches the surface exactly |
| 241 | if (params.addr == surface->addr && | 266 | if (params.addr == surface->addr && params.width == surface->width && |
| 242 | params.width == surface->width && params.height == surface->height && | 267 | params.height == surface->height && params.pixel_format == surface->pixel_format) { |
| 243 | params.pixel_format == surface->pixel_format) | ||
| 244 | { | ||
| 245 | // Make sure optional param-matching criteria are fulfilled | 268 | // Make sure optional param-matching criteria are fulfilled |
| 246 | bool tiling_match = (params.is_tiled == surface->is_tiled); | 269 | bool tiling_match = (params.is_tiled == surface->is_tiled); |
| 247 | bool res_scale_match = (params.res_scale_width == surface->res_scale_width && params.res_scale_height == surface->res_scale_height); | 270 | bool res_scale_match = (params.res_scale_width == surface->res_scale_width && |
| 271 | params.res_scale_height == surface->res_scale_height); | ||
| 248 | if (!match_res_scale || res_scale_match) { | 272 | if (!match_res_scale || res_scale_match) { |
| 249 | // Prioritize same-tiling and highest resolution surfaces | 273 | // Prioritize same-tiling and highest resolution surfaces |
| 250 | float match_goodness = (float)tiling_match + surface->res_scale_width * surface->res_scale_height; | 274 | float match_goodness = |
| 275 | (float)tiling_match + surface->res_scale_width * surface->res_scale_height; | ||
| 251 | if (match_goodness > exact_surface_goodness || surface->dirty) { | 276 | if (match_goodness > exact_surface_goodness || surface->dirty) { |
| 252 | exact_surface_goodness = match_goodness; | 277 | exact_surface_goodness = match_goodness; |
| 253 | best_exact_surface = surface; | 278 | best_exact_surface = surface; |
| @@ -288,9 +313,11 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo | |||
| 288 | 313 | ||
| 289 | if (!load_if_create) { | 314 | if (!load_if_create) { |
| 290 | // Don't load any data; just allocate the surface's texture | 315 | // Don't load any data; just allocate the surface's texture |
| 291 | AllocateSurfaceTexture(new_surface->texture.handle, new_surface->pixel_format, new_surface->GetScaledWidth(), new_surface->GetScaledHeight()); | 316 | AllocateSurfaceTexture(new_surface->texture.handle, new_surface->pixel_format, |
| 317 | new_surface->GetScaledWidth(), new_surface->GetScaledHeight()); | ||
| 292 | } else { | 318 | } else { |
| 293 | // 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 | 319 | // TODO: Consider attempting subrect match in existing surfaces and direct blit here instead |
| 320 | // of memory upload below if that's a common scenario in some game | ||
| 294 | 321 | ||
| 295 | Memory::RasterizerFlushRegion(params.addr, params_size); | 322 | Memory::RasterizerFlushRegion(params.addr, params_size); |
| 296 | 323 | ||
| @@ -318,7 +345,7 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo | |||
| 318 | tuple = fb_format_tuples[(unsigned int)params.pixel_format]; | 345 | tuple = fb_format_tuples[(unsigned int)params.pixel_format]; |
| 319 | } else { | 346 | } else { |
| 320 | // Texture | 347 | // Texture |
| 321 | tuple = { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE }; | 348 | tuple = {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}; |
| 322 | } | 349 | } |
| 323 | 350 | ||
| 324 | std::vector<Math::Vec4<u8>> tex_buffer(params.width * params.height); | 351 | std::vector<Math::Vec4<u8>> tex_buffer(params.width * params.height); |
| @@ -326,19 +353,23 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo | |||
| 326 | Pica::DebugUtils::TextureInfo tex_info; | 353 | Pica::DebugUtils::TextureInfo tex_info; |
| 327 | tex_info.width = params.width; | 354 | tex_info.width = params.width; |
| 328 | tex_info.height = params.height; | 355 | tex_info.height = params.height; |
| 329 | tex_info.stride = params.width * CachedSurface::GetFormatBpp(params.pixel_format) / 8; | 356 | tex_info.stride = |
| 357 | params.width * CachedSurface::GetFormatBpp(params.pixel_format) / 8; | ||
| 330 | tex_info.format = (Pica::Regs::TextureFormat)params.pixel_format; | 358 | tex_info.format = (Pica::Regs::TextureFormat)params.pixel_format; |
| 331 | tex_info.physical_address = params.addr; | 359 | tex_info.physical_address = params.addr; |
| 332 | 360 | ||
| 333 | for (unsigned y = 0; y < params.height; ++y) { | 361 | for (unsigned y = 0; y < params.height; ++y) { |
| 334 | for (unsigned x = 0; x < params.width; ++x) { | 362 | for (unsigned x = 0; x < params.width; ++x) { |
| 335 | tex_buffer[x + params.width * y] = Pica::DebugUtils::LookupTexture(texture_src_data, x, params.height - 1 - y, tex_info); | 363 | tex_buffer[x + params.width * y] = Pica::DebugUtils::LookupTexture( |
| 364 | texture_src_data, x, params.height - 1 - y, tex_info); | ||
| 336 | } | 365 | } |
| 337 | } | 366 | } |
| 338 | 367 | ||
| 339 | glTexImage2D(GL_TEXTURE_2D, 0, tuple.internal_format, params.width, params.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex_buffer.data()); | 368 | glTexImage2D(GL_TEXTURE_2D, 0, tuple.internal_format, params.width, params.height, |
| 369 | 0, GL_RGBA, GL_UNSIGNED_BYTE, tex_buffer.data()); | ||
| 340 | } else { | 370 | } else { |
| 341 | // Depth/Stencil formats need special treatment since they aren't sampleable using LookupTexture and can't use RGBA format | 371 | // Depth/Stencil formats need special treatment since they aren't sampleable using |
| 372 | // LookupTexture and can't use RGBA format | ||
| 342 | size_t tuple_idx = (size_t)params.pixel_format - 14; | 373 | size_t tuple_idx = (size_t)params.pixel_format - 14; |
| 343 | ASSERT(tuple_idx < depth_format_tuples.size()); | 374 | ASSERT(tuple_idx < depth_format_tuples.size()); |
| 344 | const FormatTuple& tuple = depth_format_tuples[tuple_idx]; | 375 | const FormatTuple& tuple = depth_format_tuples[tuple_idx]; |
| @@ -350,14 +381,18 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo | |||
| 350 | 381 | ||
| 351 | u32 gl_bytes_per_pixel = use_4bpp ? 4 : bytes_per_pixel; | 382 | u32 gl_bytes_per_pixel = use_4bpp ? 4 : bytes_per_pixel; |
| 352 | 383 | ||
| 353 | std::vector<u8> temp_fb_depth_buffer(params.width * params.height * gl_bytes_per_pixel); | 384 | std::vector<u8> temp_fb_depth_buffer(params.width * params.height * |
| 385 | gl_bytes_per_pixel); | ||
| 354 | 386 | ||
| 355 | u8* temp_fb_depth_buffer_ptr = use_4bpp ? temp_fb_depth_buffer.data() + 1 : temp_fb_depth_buffer.data(); | 387 | u8* temp_fb_depth_buffer_ptr = |
| 388 | use_4bpp ? temp_fb_depth_buffer.data() + 1 : temp_fb_depth_buffer.data(); | ||
| 356 | 389 | ||
| 357 | MortonCopyPixels(params.pixel_format, params.width, params.height, bytes_per_pixel, gl_bytes_per_pixel, texture_src_data, temp_fb_depth_buffer_ptr, true); | 390 | MortonCopyPixels(params.pixel_format, params.width, params.height, bytes_per_pixel, |
| 391 | gl_bytes_per_pixel, texture_src_data, temp_fb_depth_buffer_ptr, | ||
| 392 | true); | ||
| 358 | 393 | ||
| 359 | glTexImage2D(GL_TEXTURE_2D, 0, tuple.internal_format, params.width, params.height, 0, | 394 | glTexImage2D(GL_TEXTURE_2D, 0, tuple.internal_format, params.width, params.height, |
| 360 | tuple.format, tuple.type, temp_fb_depth_buffer.data()); | 395 | 0, tuple.format, tuple.type, temp_fb_depth_buffer.data()); |
| 361 | } | 396 | } |
| 362 | } | 397 | } |
| 363 | glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); | 398 | glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); |
| @@ -367,10 +402,13 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo | |||
| 367 | OGLTexture scaled_texture; | 402 | OGLTexture scaled_texture; |
| 368 | scaled_texture.Create(); | 403 | scaled_texture.Create(); |
| 369 | 404 | ||
| 370 | AllocateSurfaceTexture(scaled_texture.handle, new_surface->pixel_format, new_surface->GetScaledWidth(), new_surface->GetScaledHeight()); | 405 | AllocateSurfaceTexture(scaled_texture.handle, new_surface->pixel_format, |
| 371 | BlitTextures(new_surface->texture.handle, scaled_texture.handle, CachedSurface::GetFormatType(new_surface->pixel_format), | 406 | new_surface->GetScaledWidth(), new_surface->GetScaledHeight()); |
| 372 | MathUtil::Rectangle<int>(0, 0, new_surface->width, new_surface->height), | 407 | BlitTextures(new_surface->texture.handle, scaled_texture.handle, |
| 373 | MathUtil::Rectangle<int>(0, 0, new_surface->GetScaledWidth(), new_surface->GetScaledHeight())); | 408 | CachedSurface::GetFormatType(new_surface->pixel_format), |
| 409 | MathUtil::Rectangle<int>(0, 0, new_surface->width, new_surface->height), | ||
| 410 | MathUtil::Rectangle<int>(0, 0, new_surface->GetScaledWidth(), | ||
| 411 | new_surface->GetScaledHeight())); | ||
| 374 | 412 | ||
| 375 | new_surface->texture.Release(); | 413 | new_surface->texture.Release(); |
| 376 | new_surface->texture.handle = scaled_texture.handle; | 414 | new_surface->texture.handle = scaled_texture.handle; |
| @@ -389,11 +427,15 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo | |||
| 389 | } | 427 | } |
| 390 | 428 | ||
| 391 | Memory::RasterizerMarkRegionCached(new_surface->addr, new_surface->size, 1); | 429 | Memory::RasterizerMarkRegionCached(new_surface->addr, new_surface->size, 1); |
| 392 | 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 }))); | 430 | surface_cache.add(std::make_pair(boost::icl::interval<PAddr>::right_open( |
| 431 | new_surface->addr, new_surface->addr + new_surface->size), | ||
| 432 | std::set<std::shared_ptr<CachedSurface>>({new_surface}))); | ||
| 393 | return new_surface.get(); | 433 | return new_surface.get(); |
| 394 | } | 434 | } |
| 395 | 435 | ||
| 396 | CachedSurface* RasterizerCacheOpenGL::GetSurfaceRect(const CachedSurface& params, bool match_res_scale, bool load_if_create, MathUtil::Rectangle<int>& out_rect) { | 436 | CachedSurface* RasterizerCacheOpenGL::GetSurfaceRect(const CachedSurface& params, |
| 437 | bool match_res_scale, bool load_if_create, | ||
| 438 | MathUtil::Rectangle<int>& out_rect) { | ||
| 397 | if (params.addr == 0) { | 439 | if (params.addr == 0) { |
| 398 | return nullptr; | 440 | return nullptr; |
| 399 | } | 441 | } |
| @@ -405,7 +447,8 @@ CachedSurface* RasterizerCacheOpenGL::GetSurfaceRect(const CachedSurface& params | |||
| 405 | CachedSurface* best_subrect_surface = nullptr; | 447 | CachedSurface* best_subrect_surface = nullptr; |
| 406 | float subrect_surface_goodness = -1.f; | 448 | float subrect_surface_goodness = -1.f; |
| 407 | 449 | ||
| 408 | auto surface_interval = boost::icl::interval<PAddr>::right_open(params.addr, params.addr + params_size); | 450 | auto surface_interval = |
| 451 | boost::icl::interval<PAddr>::right_open(params.addr, params.addr + params_size); | ||
| 409 | auto cache_upper_bound = surface_cache.upper_bound(surface_interval); | 452 | auto cache_upper_bound = surface_cache.upper_bound(surface_interval); |
| 410 | for (auto it = surface_cache.lower_bound(surface_interval); it != cache_upper_bound; ++it) { | 453 | for (auto it = surface_cache.lower_bound(surface_interval); it != cache_upper_bound; ++it) { |
| 411 | for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2) { | 454 | for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2) { |
| @@ -414,14 +457,15 @@ CachedSurface* RasterizerCacheOpenGL::GetSurfaceRect(const CachedSurface& params | |||
| 414 | // Check if the request is contained in the surface | 457 | // Check if the request is contained in the surface |
| 415 | if (params.addr >= surface->addr && | 458 | if (params.addr >= surface->addr && |
| 416 | params.addr + params_size - 1 <= surface->addr + surface->size - 1 && | 459 | params.addr + params_size - 1 <= surface->addr + surface->size - 1 && |
| 417 | params.pixel_format == surface->pixel_format) | 460 | params.pixel_format == surface->pixel_format) { |
| 418 | { | ||
| 419 | // Make sure optional param-matching criteria are fulfilled | 461 | // Make sure optional param-matching criteria are fulfilled |
| 420 | bool tiling_match = (params.is_tiled == surface->is_tiled); | 462 | bool tiling_match = (params.is_tiled == surface->is_tiled); |
| 421 | bool res_scale_match = (params.res_scale_width == surface->res_scale_width && params.res_scale_height == surface->res_scale_height); | 463 | bool res_scale_match = (params.res_scale_width == surface->res_scale_width && |
| 464 | params.res_scale_height == surface->res_scale_height); | ||
| 422 | if (!match_res_scale || res_scale_match) { | 465 | if (!match_res_scale || res_scale_match) { |
| 423 | // Prioritize same-tiling and highest resolution surfaces | 466 | // Prioritize same-tiling and highest resolution surfaces |
| 424 | float match_goodness = (float)tiling_match + surface->res_scale_width * surface->res_scale_height; | 467 | float match_goodness = |
| 468 | (float)tiling_match + surface->res_scale_width * surface->res_scale_height; | ||
| 425 | if (match_goodness > subrect_surface_goodness || surface->dirty) { | 469 | if (match_goodness > subrect_surface_goodness || surface->dirty) { |
| 426 | subrect_surface_goodness = match_goodness; | 470 | subrect_surface_goodness = match_goodness; |
| 427 | best_subrect_surface = surface; | 471 | best_subrect_surface = surface; |
| @@ -433,7 +477,8 @@ CachedSurface* RasterizerCacheOpenGL::GetSurfaceRect(const CachedSurface& params | |||
| 433 | 477 | ||
| 434 | // Return the best subrect surface if found | 478 | // Return the best subrect surface if found |
| 435 | if (best_subrect_surface != nullptr) { | 479 | if (best_subrect_surface != nullptr) { |
| 436 | unsigned int bytes_per_pixel = (CachedSurface::GetFormatBpp(best_subrect_surface->pixel_format) / 8); | 480 | unsigned int bytes_per_pixel = |
| 481 | (CachedSurface::GetFormatBpp(best_subrect_surface->pixel_format) / 8); | ||
| 437 | 482 | ||
| 438 | int x0, y0; | 483 | int x0, y0; |
| 439 | 484 | ||
| @@ -452,7 +497,9 @@ CachedSurface* RasterizerCacheOpenGL::GetSurfaceRect(const CachedSurface& params | |||
| 452 | y0 = begin_tile_index / tiles_per_row * 8; | 497 | y0 = begin_tile_index / tiles_per_row * 8; |
| 453 | 498 | ||
| 454 | // Tiled surfaces are flipped vertically in the rasterizer vs. 3DS memory. | 499 | // Tiled surfaces are flipped vertically in the rasterizer vs. 3DS memory. |
| 455 | out_rect = MathUtil::Rectangle<int>(x0, best_subrect_surface->height - y0, x0 + params.width, best_subrect_surface->height - (y0 + params.height)); | 500 | out_rect = |
| 501 | MathUtil::Rectangle<int>(x0, best_subrect_surface->height - y0, x0 + params.width, | ||
| 502 | best_subrect_surface->height - (y0 + params.height)); | ||
| 456 | } | 503 | } |
| 457 | 504 | ||
| 458 | out_rect.left = (int)(out_rect.left * best_subrect_surface->res_scale_width); | 505 | out_rect.left = (int)(out_rect.left * best_subrect_surface->res_scale_width); |
| @@ -465,16 +512,20 @@ CachedSurface* RasterizerCacheOpenGL::GetSurfaceRect(const CachedSurface& params | |||
| 465 | 512 | ||
| 466 | // No subrect found - create and return a new surface | 513 | // No subrect found - create and return a new surface |
| 467 | if (!params.is_tiled) { | 514 | if (!params.is_tiled) { |
| 468 | out_rect = MathUtil::Rectangle<int>(0, 0, (int)(params.width * params.res_scale_width), (int)(params.height * params.res_scale_height)); | 515 | out_rect = MathUtil::Rectangle<int>(0, 0, (int)(params.width * params.res_scale_width), |
| 516 | (int)(params.height * params.res_scale_height)); | ||
| 469 | } else { | 517 | } else { |
| 470 | out_rect = MathUtil::Rectangle<int>(0, (int)(params.height * params.res_scale_height), (int)(params.width * params.res_scale_width), 0); | 518 | out_rect = MathUtil::Rectangle<int>(0, (int)(params.height * params.res_scale_height), |
| 519 | (int)(params.width * params.res_scale_width), 0); | ||
| 471 | } | 520 | } |
| 472 | 521 | ||
| 473 | return GetSurface(params, match_res_scale, load_if_create); | 522 | return GetSurface(params, match_res_scale, load_if_create); |
| 474 | } | 523 | } |
| 475 | 524 | ||
| 476 | CachedSurface* RasterizerCacheOpenGL::GetTextureSurface(const Pica::Regs::FullTextureConfig& config) { | 525 | CachedSurface* |
| 477 | Pica::DebugUtils::TextureInfo info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config.config, config.format); | 526 | RasterizerCacheOpenGL::GetTextureSurface(const Pica::Regs::FullTextureConfig& config) { |
| 527 | Pica::DebugUtils::TextureInfo info = | ||
| 528 | Pica::DebugUtils::TextureInfo::FromPicaRegister(config.config, config.format); | ||
| 478 | 529 | ||
| 479 | CachedSurface params; | 530 | CachedSurface params; |
| 480 | params.addr = info.physical_address; | 531 | params.addr = info.physical_address; |
| @@ -485,20 +536,28 @@ CachedSurface* RasterizerCacheOpenGL::GetTextureSurface(const Pica::Regs::FullTe | |||
| 485 | return GetSurface(params, false, true); | 536 | return GetSurface(params, false, true); |
| 486 | } | 537 | } |
| 487 | 538 | ||
| 488 | std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> RasterizerCacheOpenGL::GetFramebufferSurfaces(const Pica::Regs::FramebufferConfig& config) { | 539 | std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> |
| 540 | RasterizerCacheOpenGL::GetFramebufferSurfaces(const Pica::Regs::FramebufferConfig& config) { | ||
| 489 | const auto& regs = Pica::g_state.regs; | 541 | const auto& regs = Pica::g_state.regs; |
| 490 | 542 | ||
| 491 | // Make sur that framebuffers don't overlap if both color and depth are being used | 543 | // Make sur that framebuffers don't overlap if both color and depth are being used |
| 492 | u32 fb_area = config.GetWidth() * config.GetHeight(); | 544 | u32 fb_area = config.GetWidth() * config.GetHeight(); |
| 493 | bool framebuffers_overlap = config.GetColorBufferPhysicalAddress() != 0 && | 545 | bool framebuffers_overlap = |
| 494 | config.GetDepthBufferPhysicalAddress() != 0 && | 546 | config.GetColorBufferPhysicalAddress() != 0 && |
| 495 | MathUtil::IntervalsIntersect(config.GetColorBufferPhysicalAddress(), fb_area * GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(config.color_format.Value())), | 547 | config.GetDepthBufferPhysicalAddress() != 0 && |
| 496 | config.GetDepthBufferPhysicalAddress(), fb_area * Pica::Regs::BytesPerDepthPixel(config.depth_format)); | 548 | MathUtil::IntervalsIntersect( |
| 549 | config.GetColorBufferPhysicalAddress(), | ||
| 550 | fb_area * GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(config.color_format.Value())), | ||
| 551 | config.GetDepthBufferPhysicalAddress(), | ||
| 552 | fb_area * Pica::Regs::BytesPerDepthPixel(config.depth_format)); | ||
| 497 | bool using_color_fb = config.GetColorBufferPhysicalAddress() != 0; | 553 | bool using_color_fb = config.GetColorBufferPhysicalAddress() != 0; |
| 498 | bool using_depth_fb = config.GetDepthBufferPhysicalAddress() != 0 && (regs.output_merger.depth_test_enable || regs.output_merger.depth_write_enable || !framebuffers_overlap); | 554 | bool using_depth_fb = config.GetDepthBufferPhysicalAddress() != 0 && |
| 555 | (regs.output_merger.depth_test_enable || | ||
| 556 | regs.output_merger.depth_write_enable || !framebuffers_overlap); | ||
| 499 | 557 | ||
| 500 | if (framebuffers_overlap && using_color_fb && using_depth_fb) { | 558 | if (framebuffers_overlap && using_color_fb && using_depth_fb) { |
| 501 | LOG_CRITICAL(Render_OpenGL, "Color and depth framebuffer memory regions overlap; overlapping framebuffers not supported!"); | 559 | LOG_CRITICAL(Render_OpenGL, "Color and depth framebuffer memory regions overlap; " |
| 560 | "overlapping framebuffers not supported!"); | ||
| 502 | using_depth_fb = false; | 561 | using_depth_fb = false; |
| 503 | } | 562 | } |
| 504 | 563 | ||
| @@ -512,8 +571,10 @@ std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> RasterizerC | |||
| 512 | auto layout = VideoCore::g_emu_window->GetFramebufferLayout(); | 571 | auto layout = VideoCore::g_emu_window->GetFramebufferLayout(); |
| 513 | 572 | ||
| 514 | // Assume same scaling factor for top and bottom screens | 573 | // Assume same scaling factor for top and bottom screens |
| 515 | color_params.res_scale_width = depth_params.res_scale_width = (float)layout.top_screen.GetWidth() / VideoCore::kScreenTopWidth; | 574 | color_params.res_scale_width = depth_params.res_scale_width = |
| 516 | color_params.res_scale_height = depth_params.res_scale_height = (float)layout.top_screen.GetHeight() / VideoCore::kScreenTopHeight; | 575 | (float)layout.top_screen.GetWidth() / VideoCore::kScreenTopWidth; |
| 576 | color_params.res_scale_height = depth_params.res_scale_height = | ||
| 577 | (float)layout.top_screen.GetHeight() / VideoCore::kScreenTopHeight; | ||
| 517 | } | 578 | } |
| 518 | 579 | ||
| 519 | color_params.addr = config.GetColorBufferPhysicalAddress(); | 580 | color_params.addr = config.GetColorBufferPhysicalAddress(); |
| @@ -523,22 +584,28 @@ std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> RasterizerC | |||
| 523 | depth_params.pixel_format = CachedSurface::PixelFormatFromDepthFormat(config.depth_format); | 584 | depth_params.pixel_format = CachedSurface::PixelFormatFromDepthFormat(config.depth_format); |
| 524 | 585 | ||
| 525 | MathUtil::Rectangle<int> color_rect; | 586 | MathUtil::Rectangle<int> color_rect; |
| 526 | CachedSurface* color_surface = using_color_fb ? GetSurfaceRect(color_params, true, true, color_rect) : nullptr; | 587 | CachedSurface* color_surface = |
| 588 | using_color_fb ? GetSurfaceRect(color_params, true, true, color_rect) : nullptr; | ||
| 527 | 589 | ||
| 528 | MathUtil::Rectangle<int> depth_rect; | 590 | MathUtil::Rectangle<int> depth_rect; |
| 529 | CachedSurface* depth_surface = using_depth_fb ? GetSurfaceRect(depth_params, true, true, depth_rect) : nullptr; | 591 | CachedSurface* depth_surface = |
| 592 | using_depth_fb ? GetSurfaceRect(depth_params, true, true, depth_rect) : nullptr; | ||
| 530 | 593 | ||
| 531 | // Sanity check to make sure found surfaces aren't the same | 594 | // Sanity check to make sure found surfaces aren't the same |
| 532 | if (using_depth_fb && using_color_fb && color_surface == depth_surface) { | 595 | if (using_depth_fb && using_color_fb && color_surface == depth_surface) { |
| 533 | LOG_CRITICAL(Render_OpenGL, "Color and depth framebuffer surfaces overlap; overlapping surfaces not supported!"); | 596 | LOG_CRITICAL( |
| 597 | Render_OpenGL, | ||
| 598 | "Color and depth framebuffer surfaces overlap; overlapping surfaces not supported!"); | ||
| 534 | using_depth_fb = false; | 599 | using_depth_fb = false; |
| 535 | depth_surface = nullptr; | 600 | depth_surface = nullptr; |
| 536 | } | 601 | } |
| 537 | 602 | ||
| 538 | MathUtil::Rectangle<int> rect; | 603 | MathUtil::Rectangle<int> rect; |
| 539 | 604 | ||
| 540 | if (color_surface != nullptr && depth_surface != nullptr && (depth_rect.left != color_rect.left || depth_rect.top != color_rect.top)) { | 605 | if (color_surface != nullptr && depth_surface != nullptr && |
| 541 | // Can't specify separate color and depth viewport offsets in OpenGL, so re-zero both if they don't match | 606 | (depth_rect.left != color_rect.left || depth_rect.top != color_rect.top)) { |
| 607 | // Can't specify separate color and depth viewport offsets in OpenGL, so re-zero both if | ||
| 608 | // they don't match | ||
| 542 | if (color_rect.left != 0 || color_rect.top != 0) { | 609 | if (color_rect.left != 0 || color_rect.top != 0) { |
| 543 | color_surface = GetSurface(color_params, true, true); | 610 | color_surface = GetSurface(color_params, true, true); |
| 544 | } | 611 | } |
| @@ -548,9 +615,13 @@ std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> RasterizerC | |||
| 548 | } | 615 | } |
| 549 | 616 | ||
| 550 | if (!color_surface->is_tiled) { | 617 | if (!color_surface->is_tiled) { |
| 551 | rect = MathUtil::Rectangle<int>(0, 0, (int)(color_params.width * color_params.res_scale_width), (int)(color_params.height * color_params.res_scale_height)); | 618 | rect = MathUtil::Rectangle<int>( |
| 619 | 0, 0, (int)(color_params.width * color_params.res_scale_width), | ||
| 620 | (int)(color_params.height * color_params.res_scale_height)); | ||
| 552 | } else { | 621 | } else { |
| 553 | rect = MathUtil::Rectangle<int>(0, (int)(color_params.height * color_params.res_scale_height), (int)(color_params.width * color_params.res_scale_width), 0); | 622 | rect = MathUtil::Rectangle<int>( |
| 623 | 0, (int)(color_params.height * color_params.res_scale_height), | ||
| 624 | (int)(color_params.width * color_params.res_scale_width), 0); | ||
| 554 | } | 625 | } |
| 555 | } else if (color_surface != nullptr) { | 626 | } else if (color_surface != nullptr) { |
| 556 | rect = color_rect; | 627 | rect = color_rect; |
| @@ -564,7 +635,8 @@ std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> RasterizerC | |||
| 564 | } | 635 | } |
| 565 | 636 | ||
| 566 | CachedSurface* RasterizerCacheOpenGL::TryGetFillSurface(const GPU::Regs::MemoryFillConfig& config) { | 637 | CachedSurface* RasterizerCacheOpenGL::TryGetFillSurface(const GPU::Regs::MemoryFillConfig& config) { |
| 567 | auto surface_interval = boost::icl::interval<PAddr>::right_open(config.GetStartAddress(), config.GetEndAddress()); | 638 | auto surface_interval = |
| 639 | boost::icl::interval<PAddr>::right_open(config.GetStartAddress(), config.GetEndAddress()); | ||
| 568 | auto range = surface_cache.equal_range(surface_interval); | 640 | auto range = surface_cache.equal_range(surface_interval); |
| 569 | for (auto it = range.first; it != range.second; ++it) { | 641 | for (auto it = range.first; it != range.second; ++it) { |
| 570 | for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2) { | 642 | for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2) { |
| @@ -581,8 +653,9 @@ CachedSurface* RasterizerCacheOpenGL::TryGetFillSurface(const GPU::Regs::MemoryF | |||
| 581 | 653 | ||
| 582 | if (surface->addr == config.GetStartAddress() && | 654 | if (surface->addr == config.GetStartAddress() && |
| 583 | CachedSurface::GetFormatBpp(surface->pixel_format) == bits_per_value && | 655 | CachedSurface::GetFormatBpp(surface->pixel_format) == bits_per_value && |
| 584 | (surface->width * surface->height * CachedSurface::GetFormatBpp(surface->pixel_format) / 8) == (config.GetEndAddress() - config.GetStartAddress())) | 656 | (surface->width * surface->height * |
| 585 | { | 657 | CachedSurface::GetFormatBpp(surface->pixel_format) / 8) == |
| 658 | (config.GetEndAddress() - config.GetStartAddress())) { | ||
| 586 | return surface; | 659 | return surface; |
| 587 | } | 660 | } |
| 588 | } | 661 | } |
| @@ -617,8 +690,11 @@ void RasterizerCacheOpenGL::FlushSurface(CachedSurface* surface) { | |||
| 617 | if (surface->res_scale_width != 1.f || surface->res_scale_height != 1.f) { | 690 | if (surface->res_scale_width != 1.f || surface->res_scale_height != 1.f) { |
| 618 | unscaled_tex.Create(); | 691 | unscaled_tex.Create(); |
| 619 | 692 | ||
| 620 | AllocateSurfaceTexture(unscaled_tex.handle, surface->pixel_format, surface->width, surface->height); | 693 | AllocateSurfaceTexture(unscaled_tex.handle, surface->pixel_format, surface->width, |
| 621 | BlitTextures(surface->texture.handle, unscaled_tex.handle, CachedSurface::GetFormatType(surface->pixel_format), | 694 | surface->height); |
| 695 | BlitTextures( | ||
| 696 | surface->texture.handle, unscaled_tex.handle, | ||
| 697 | CachedSurface::GetFormatType(surface->pixel_format), | ||
| 622 | MathUtil::Rectangle<int>(0, 0, surface->GetScaledWidth(), surface->GetScaledHeight()), | 698 | MathUtil::Rectangle<int>(0, 0, surface->GetScaledWidth(), surface->GetScaledHeight()), |
| 623 | MathUtil::Rectangle<int>(0, 0, surface->width, surface->height)); | 699 | MathUtil::Rectangle<int>(0, 0, surface->width, surface->height)); |
| 624 | 700 | ||
| @@ -648,10 +724,14 @@ void RasterizerCacheOpenGL::FlushSurface(CachedSurface* surface) { | |||
| 648 | 724 | ||
| 649 | glGetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type, temp_gl_buffer.data()); | 725 | glGetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type, temp_gl_buffer.data()); |
| 650 | 726 | ||
| 651 | // Directly copy pixels. Internal OpenGL color formats are consistent so no conversion is necessary. | 727 | // Directly copy pixels. Internal OpenGL color formats are consistent so no conversion |
| 652 | MortonCopyPixels(surface->pixel_format, surface->width, surface->height, bytes_per_pixel, bytes_per_pixel, dst_buffer, temp_gl_buffer.data(), false); | 728 | // is necessary. |
| 729 | MortonCopyPixels(surface->pixel_format, surface->width, surface->height, | ||
| 730 | bytes_per_pixel, bytes_per_pixel, dst_buffer, temp_gl_buffer.data(), | ||
| 731 | false); | ||
| 653 | } else { | 732 | } else { |
| 654 | // Depth/Stencil formats need special treatment since they aren't sampleable using LookupTexture and can't use RGBA format | 733 | // Depth/Stencil formats need special treatment since they aren't sampleable using |
| 734 | // LookupTexture and can't use RGBA format | ||
| 655 | size_t tuple_idx = (size_t)surface->pixel_format - 14; | 735 | size_t tuple_idx = (size_t)surface->pixel_format - 14; |
| 656 | ASSERT(tuple_idx < depth_format_tuples.size()); | 736 | ASSERT(tuple_idx < depth_format_tuples.size()); |
| 657 | const FormatTuple& tuple = depth_format_tuples[tuple_idx]; | 737 | const FormatTuple& tuple = depth_format_tuples[tuple_idx]; |
| @@ -669,7 +749,9 @@ void RasterizerCacheOpenGL::FlushSurface(CachedSurface* surface) { | |||
| 669 | 749 | ||
| 670 | u8* temp_gl_buffer_ptr = use_4bpp ? temp_gl_buffer.data() + 1 : temp_gl_buffer.data(); | 750 | u8* temp_gl_buffer_ptr = use_4bpp ? temp_gl_buffer.data() + 1 : temp_gl_buffer.data(); |
| 671 | 751 | ||
| 672 | MortonCopyPixels(surface->pixel_format, surface->width, surface->height, bytes_per_pixel, gl_bytes_per_pixel, dst_buffer, temp_gl_buffer_ptr, false); | 752 | MortonCopyPixels(surface->pixel_format, surface->width, surface->height, |
| 753 | bytes_per_pixel, gl_bytes_per_pixel, dst_buffer, temp_gl_buffer_ptr, | ||
| 754 | false); | ||
| 673 | } | 755 | } |
| 674 | } | 756 | } |
| 675 | glPixelStorei(GL_PACK_ROW_LENGTH, 0); | 757 | glPixelStorei(GL_PACK_ROW_LENGTH, 0); |
| @@ -680,7 +762,8 @@ void RasterizerCacheOpenGL::FlushSurface(CachedSurface* surface) { | |||
| 680 | cur_state.Apply(); | 762 | cur_state.Apply(); |
| 681 | } | 763 | } |
| 682 | 764 | ||
| 683 | void RasterizerCacheOpenGL::FlushRegion(PAddr addr, u32 size, const CachedSurface* skip_surface, bool invalidate) { | 765 | void RasterizerCacheOpenGL::FlushRegion(PAddr addr, u32 size, const CachedSurface* skip_surface, |
| 766 | bool invalidate) { | ||
| 684 | if (size == 0) { | 767 | if (size == 0) { |
| 685 | return; | 768 | return; |
| 686 | } | 769 | } |
| @@ -691,8 +774,11 @@ void RasterizerCacheOpenGL::FlushRegion(PAddr addr, u32 size, const CachedSurfac | |||
| 691 | auto surface_interval = boost::icl::interval<PAddr>::right_open(addr, addr + size); | 774 | auto surface_interval = boost::icl::interval<PAddr>::right_open(addr, addr + size); |
| 692 | auto cache_upper_bound = surface_cache.upper_bound(surface_interval); | 775 | auto cache_upper_bound = surface_cache.upper_bound(surface_interval); |
| 693 | for (auto it = surface_cache.lower_bound(surface_interval); it != cache_upper_bound; ++it) { | 776 | for (auto it = surface_cache.lower_bound(surface_interval); it != cache_upper_bound; ++it) { |
| 694 | std::copy_if(it->second.begin(), it->second.end(), std::inserter(touching_surfaces, touching_surfaces.end()), | 777 | std::copy_if(it->second.begin(), it->second.end(), |
| 695 | [skip_surface](std::shared_ptr<CachedSurface> surface) { return (surface.get() != skip_surface); }); | 778 | std::inserter(touching_surfaces, touching_surfaces.end()), |
| 779 | [skip_surface](std::shared_ptr<CachedSurface> surface) { | ||
| 780 | return (surface.get() != skip_surface); | ||
| 781 | }); | ||
| 696 | } | 782 | } |
| 697 | 783 | ||
| 698 | // Flush and invalidate surfaces | 784 | // Flush and invalidate surfaces |
| @@ -700,7 +786,10 @@ void RasterizerCacheOpenGL::FlushRegion(PAddr addr, u32 size, const CachedSurfac | |||
| 700 | FlushSurface(surface.get()); | 786 | FlushSurface(surface.get()); |
| 701 | if (invalidate) { | 787 | if (invalidate) { |
| 702 | Memory::RasterizerMarkRegionCached(surface->addr, surface->size, -1); | 788 | Memory::RasterizerMarkRegionCached(surface->addr, surface->size, -1); |
| 703 | 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 }))); | 789 | surface_cache.subtract( |
| 790 | std::make_pair(boost::icl::interval<PAddr>::right_open( | ||
| 791 | surface->addr, surface->addr + surface->size), | ||
| 792 | std::set<std::shared_ptr<CachedSurface>>({surface}))); | ||
| 704 | } | 793 | } |
| 705 | } | 794 | } |
| 706 | } | 795 | } |
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 @@ | |||
| 22 | #include "video_core/renderer_opengl/gl_resource_manager.h" | 22 | #include "video_core/renderer_opengl/gl_resource_manager.h" |
| 23 | 23 | ||
| 24 | namespace MathUtil { | 24 | namespace MathUtil { |
| 25 | template <class T> struct Rectangle; | 25 | template <class T> |
| 26 | struct Rectangle; | ||
| 26 | } | 27 | } |
| 27 | 28 | ||
| 28 | struct CachedSurface; | 29 | struct CachedSurface; |
| @@ -32,38 +33,38 @@ using SurfaceCache = boost::icl::interval_map<PAddr, std::set<std::shared_ptr<Ca | |||
| 32 | struct CachedSurface { | 33 | struct CachedSurface { |
| 33 | enum class PixelFormat { | 34 | enum class PixelFormat { |
| 34 | // First 5 formats are shared between textures and color buffers | 35 | // First 5 formats are shared between textures and color buffers |
| 35 | RGBA8 = 0, | 36 | RGBA8 = 0, |
| 36 | RGB8 = 1, | 37 | RGB8 = 1, |
| 37 | RGB5A1 = 2, | 38 | RGB5A1 = 2, |
| 38 | RGB565 = 3, | 39 | RGB565 = 3, |
| 39 | RGBA4 = 4, | 40 | RGBA4 = 4, |
| 40 | 41 | ||
| 41 | // Texture-only formats | 42 | // Texture-only formats |
| 42 | IA8 = 5, | 43 | IA8 = 5, |
| 43 | RG8 = 6, | 44 | RG8 = 6, |
| 44 | I8 = 7, | 45 | I8 = 7, |
| 45 | A8 = 8, | 46 | A8 = 8, |
| 46 | IA4 = 9, | 47 | IA4 = 9, |
| 47 | I4 = 10, | 48 | I4 = 10, |
| 48 | A4 = 11, | 49 | A4 = 11, |
| 49 | ETC1 = 12, | 50 | ETC1 = 12, |
| 50 | ETC1A4 = 13, | 51 | ETC1A4 = 13, |
| 51 | 52 | ||
| 52 | // Depth buffer-only formats | 53 | // Depth buffer-only formats |
| 53 | D16 = 14, | 54 | D16 = 14, |
| 54 | // gap | 55 | // gap |
| 55 | D24 = 16, | 56 | D24 = 16, |
| 56 | D24S8 = 17, | 57 | D24S8 = 17, |
| 57 | 58 | ||
| 58 | Invalid = 255, | 59 | Invalid = 255, |
| 59 | }; | 60 | }; |
| 60 | 61 | ||
| 61 | enum class SurfaceType { | 62 | enum class SurfaceType { |
| 62 | Color = 0, | 63 | Color = 0, |
| 63 | Texture = 1, | 64 | Texture = 1, |
| 64 | Depth = 2, | 65 | Depth = 2, |
| 65 | DepthStencil = 3, | 66 | DepthStencil = 3, |
| 66 | Invalid = 4, | 67 | Invalid = 4, |
| 67 | }; | 68 | }; |
| 68 | 69 | ||
| 69 | static unsigned int GetFormatBpp(CachedSurface::PixelFormat format) { | 70 | static unsigned int GetFormatBpp(CachedSurface::PixelFormat format) { |
| @@ -101,7 +102,8 @@ struct CachedSurface { | |||
| 101 | } | 102 | } |
| 102 | 103 | ||
| 103 | static PixelFormat PixelFormatFromDepthFormat(Pica::Regs::DepthFormat format) { | 104 | static PixelFormat PixelFormatFromDepthFormat(Pica::Regs::DepthFormat format) { |
| 104 | return ((unsigned int)format < 4) ? (PixelFormat)((unsigned int)format + 14) : PixelFormat::Invalid; | 105 | return ((unsigned int)format < 4) ? (PixelFormat)((unsigned int)format + 14) |
| 106 | : PixelFormat::Invalid; | ||
| 105 | } | 107 | } |
| 106 | 108 | ||
| 107 | static PixelFormat PixelFormatFromGPUPixelFormat(GPU::Regs::PixelFormat format) { | 109 | static PixelFormat PixelFormatFromGPUPixelFormat(GPU::Regs::PixelFormat format) { |
| @@ -120,7 +122,8 @@ struct CachedSurface { | |||
| 120 | SurfaceType a_type = GetFormatType(pixel_format_a); | 122 | SurfaceType a_type = GetFormatType(pixel_format_a); |
| 121 | SurfaceType b_type = GetFormatType(pixel_format_b); | 123 | SurfaceType b_type = GetFormatType(pixel_format_b); |
| 122 | 124 | ||
| 123 | if ((a_type == SurfaceType::Color || a_type == SurfaceType::Texture) && (b_type == SurfaceType::Color || b_type == SurfaceType::Texture)) { | 125 | if ((a_type == SurfaceType::Color || a_type == SurfaceType::Texture) && |
| 126 | (b_type == SurfaceType::Color || b_type == SurfaceType::Texture)) { | ||
| 124 | return true; | 127 | return true; |
| 125 | } | 128 | } |
| 126 | 129 | ||
| @@ -187,22 +190,30 @@ public: | |||
| 187 | ~RasterizerCacheOpenGL(); | 190 | ~RasterizerCacheOpenGL(); |
| 188 | 191 | ||
| 189 | /// Blits one texture to another | 192 | /// Blits one texture to another |
| 190 | bool BlitTextures(GLuint src_tex, GLuint dst_tex, CachedSurface::SurfaceType type, const MathUtil::Rectangle<int>& src_rect, const MathUtil::Rectangle<int>& dst_rect); | 193 | bool BlitTextures(GLuint src_tex, GLuint dst_tex, CachedSurface::SurfaceType type, |
| 194 | const MathUtil::Rectangle<int>& src_rect, | ||
| 195 | const MathUtil::Rectangle<int>& dst_rect); | ||
| 191 | 196 | ||
| 192 | /// Attempt to blit one surface's texture to another | 197 | /// Attempt to blit one surface's texture to another |
| 193 | bool TryBlitSurfaces(CachedSurface* src_surface, const MathUtil::Rectangle<int>& src_rect, CachedSurface* dst_surface, const MathUtil::Rectangle<int>& dst_rect); | 198 | bool TryBlitSurfaces(CachedSurface* src_surface, const MathUtil::Rectangle<int>& src_rect, |
| 199 | CachedSurface* dst_surface, const MathUtil::Rectangle<int>& dst_rect); | ||
| 194 | 200 | ||
| 195 | /// Loads a texture from 3DS memory to OpenGL and caches it (if not already cached) | 201 | /// Loads a texture from 3DS memory to OpenGL and caches it (if not already cached) |
| 196 | CachedSurface* GetSurface(const CachedSurface& params, bool match_res_scale, bool load_if_create); | 202 | CachedSurface* GetSurface(const CachedSurface& params, bool match_res_scale, |
| 203 | bool load_if_create); | ||
| 197 | 204 | ||
| 198 | /// 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) | 205 | /// Attempt to find a subrect (resolution scaled) of a surface, otherwise loads a texture from |
| 199 | CachedSurface* GetSurfaceRect(const CachedSurface& params, bool match_res_scale, bool load_if_create, MathUtil::Rectangle<int>& out_rect); | 206 | /// 3DS memory to OpenGL and caches it (if not already cached) |
| 207 | CachedSurface* GetSurfaceRect(const CachedSurface& params, bool match_res_scale, | ||
| 208 | bool load_if_create, MathUtil::Rectangle<int>& out_rect); | ||
| 200 | 209 | ||
| 201 | /// Gets a surface based on the texture configuration | 210 | /// Gets a surface based on the texture configuration |
| 202 | CachedSurface* GetTextureSurface(const Pica::Regs::FullTextureConfig& config); | 211 | CachedSurface* GetTextureSurface(const Pica::Regs::FullTextureConfig& config); |
| 203 | 212 | ||
| 204 | /// Gets the color and depth surfaces and rect (resolution scaled) based on the framebuffer configuration | 213 | /// Gets the color and depth surfaces and rect (resolution scaled) based on the framebuffer |
| 205 | std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> GetFramebufferSurfaces(const Pica::Regs::FramebufferConfig& config); | 214 | /// configuration |
| 215 | std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> | ||
| 216 | GetFramebufferSurfaces(const Pica::Regs::FramebufferConfig& config); | ||
| 206 | 217 | ||
| 207 | /// Attempt to get a surface that exactly matches the fill region and format | 218 | /// Attempt to get a surface that exactly matches the fill region and format |
| 208 | CachedSurface* TryGetFillSurface(const GPU::Regs::MemoryFillConfig& config); | 219 | CachedSurface* TryGetFillSurface(const GPU::Regs::MemoryFillConfig& config); |
| @@ -210,7 +221,8 @@ public: | |||
| 210 | /// Write the surface back to memory | 221 | /// Write the surface back to memory |
| 211 | void FlushSurface(CachedSurface* surface); | 222 | void FlushSurface(CachedSurface* surface); |
| 212 | 223 | ||
| 213 | /// Write any cached resources overlapping the region back to memory (if dirty) and optionally invalidate them in the cache | 224 | /// Write any cached resources overlapping the region back to memory (if dirty) and optionally |
| 225 | /// invalidate them in the cache | ||
| 214 | void FlushRegion(PAddr addr, u32 size, const CachedSurface* skip_surface, bool invalidate); | 226 | void FlushRegion(PAddr addr, u32 size, const CachedSurface* skip_surface, bool invalidate); |
| 215 | 227 | ||
| 216 | /// Flush all cached resources tracked by this cache manager | 228 | /// 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 @@ | |||
| 16 | class OGLTexture : private NonCopyable { | 16 | class OGLTexture : private NonCopyable { |
| 17 | public: | 17 | public: |
| 18 | OGLTexture() = default; | 18 | OGLTexture() = default; |
| 19 | OGLTexture(OGLTexture&& o) { std::swap(handle, o.handle); } | 19 | OGLTexture(OGLTexture&& o) { |
| 20 | ~OGLTexture() { Release(); } | 20 | std::swap(handle, o.handle); |
| 21 | OGLTexture& operator=(OGLTexture&& o) { std::swap(handle, o.handle); return *this; } | 21 | } |
| 22 | ~OGLTexture() { | ||
| 23 | Release(); | ||
| 24 | } | ||
| 25 | OGLTexture& operator=(OGLTexture&& o) { | ||
| 26 | std::swap(handle, o.handle); | ||
| 27 | return *this; | ||
| 28 | } | ||
| 22 | 29 | ||
| 23 | /// Creates a new internal OpenGL resource and stores the handle | 30 | /// Creates a new internal OpenGL resource and stores the handle |
| 24 | void Create() { | 31 | void Create() { |
| 25 | if (handle != 0) return; | 32 | if (handle != 0) |
| 33 | return; | ||
| 26 | glGenTextures(1, &handle); | 34 | glGenTextures(1, &handle); |
| 27 | } | 35 | } |
| 28 | 36 | ||
| 29 | /// Deletes the internal OpenGL resource | 37 | /// Deletes the internal OpenGL resource |
| 30 | void Release() { | 38 | void Release() { |
| 31 | if (handle == 0) return; | 39 | if (handle == 0) |
| 40 | return; | ||
| 32 | glDeleteTextures(1, &handle); | 41 | glDeleteTextures(1, &handle); |
| 33 | OpenGLState::ResetTexture(handle); | 42 | OpenGLState::ResetTexture(handle); |
| 34 | handle = 0; | 43 | handle = 0; |
| @@ -40,19 +49,28 @@ public: | |||
| 40 | class OGLSampler : private NonCopyable { | 49 | class OGLSampler : private NonCopyable { |
| 41 | public: | 50 | public: |
| 42 | OGLSampler() = default; | 51 | OGLSampler() = default; |
| 43 | OGLSampler(OGLSampler&& o) { std::swap(handle, o.handle); } | 52 | OGLSampler(OGLSampler&& o) { |
| 44 | ~OGLSampler() { Release(); } | 53 | std::swap(handle, o.handle); |
| 45 | OGLSampler& operator=(OGLSampler&& o) { std::swap(handle, o.handle); return *this; } | 54 | } |
| 55 | ~OGLSampler() { | ||
| 56 | Release(); | ||
| 57 | } | ||
| 58 | OGLSampler& operator=(OGLSampler&& o) { | ||
| 59 | std::swap(handle, o.handle); | ||
| 60 | return *this; | ||
| 61 | } | ||
| 46 | 62 | ||
| 47 | /// Creates a new internal OpenGL resource and stores the handle | 63 | /// Creates a new internal OpenGL resource and stores the handle |
| 48 | void Create() { | 64 | void Create() { |
| 49 | if (handle != 0) return; | 65 | if (handle != 0) |
| 66 | return; | ||
| 50 | glGenSamplers(1, &handle); | 67 | glGenSamplers(1, &handle); |
| 51 | } | 68 | } |
| 52 | 69 | ||
| 53 | /// Deletes the internal OpenGL resource | 70 | /// Deletes the internal OpenGL resource |
| 54 | void Release() { | 71 | void Release() { |
| 55 | if (handle == 0) return; | 72 | if (handle == 0) |
| 73 | return; | ||
| 56 | glDeleteSamplers(1, &handle); | 74 | glDeleteSamplers(1, &handle); |
| 57 | OpenGLState::ResetSampler(handle); | 75 | OpenGLState::ResetSampler(handle); |
| 58 | handle = 0; | 76 | handle = 0; |
| @@ -64,19 +82,28 @@ public: | |||
| 64 | class OGLShader : private NonCopyable { | 82 | class OGLShader : private NonCopyable { |
| 65 | public: | 83 | public: |
| 66 | OGLShader() = default; | 84 | OGLShader() = default; |
| 67 | OGLShader(OGLShader&& o) { std::swap(handle, o.handle); } | 85 | OGLShader(OGLShader&& o) { |
| 68 | ~OGLShader() { Release(); } | 86 | std::swap(handle, o.handle); |
| 69 | OGLShader& operator=(OGLShader&& o) { std::swap(handle, o.handle); return *this; } | 87 | } |
| 88 | ~OGLShader() { | ||
| 89 | Release(); | ||
| 90 | } | ||
| 91 | OGLShader& operator=(OGLShader&& o) { | ||
| 92 | std::swap(handle, o.handle); | ||
| 93 | return *this; | ||
| 94 | } | ||
| 70 | 95 | ||
| 71 | /// Creates a new internal OpenGL resource and stores the handle | 96 | /// Creates a new internal OpenGL resource and stores the handle |
| 72 | void Create(const char* vert_shader, const char* frag_shader) { | 97 | void Create(const char* vert_shader, const char* frag_shader) { |
| 73 | if (handle != 0) return; | 98 | if (handle != 0) |
| 99 | return; | ||
| 74 | handle = GLShader::LoadProgram(vert_shader, frag_shader); | 100 | handle = GLShader::LoadProgram(vert_shader, frag_shader); |
| 75 | } | 101 | } |
| 76 | 102 | ||
| 77 | /// Deletes the internal OpenGL resource | 103 | /// Deletes the internal OpenGL resource |
| 78 | void Release() { | 104 | void Release() { |
| 79 | if (handle == 0) return; | 105 | if (handle == 0) |
| 106 | return; | ||
| 80 | glDeleteProgram(handle); | 107 | glDeleteProgram(handle); |
| 81 | OpenGLState::ResetProgram(handle); | 108 | OpenGLState::ResetProgram(handle); |
| 82 | handle = 0; | 109 | handle = 0; |
| @@ -88,19 +115,28 @@ public: | |||
| 88 | class OGLBuffer : private NonCopyable { | 115 | class OGLBuffer : private NonCopyable { |
| 89 | public: | 116 | public: |
| 90 | OGLBuffer() = default; | 117 | OGLBuffer() = default; |
| 91 | OGLBuffer(OGLBuffer&& o) { std::swap(handle, o.handle); } | 118 | OGLBuffer(OGLBuffer&& o) { |
| 92 | ~OGLBuffer() { Release(); } | 119 | std::swap(handle, o.handle); |
| 93 | OGLBuffer& operator=(OGLBuffer&& o) { std::swap(handle, o.handle); return *this; } | 120 | } |
| 121 | ~OGLBuffer() { | ||
| 122 | Release(); | ||
| 123 | } | ||
| 124 | OGLBuffer& operator=(OGLBuffer&& o) { | ||
| 125 | std::swap(handle, o.handle); | ||
| 126 | return *this; | ||
| 127 | } | ||
| 94 | 128 | ||
| 95 | /// Creates a new internal OpenGL resource and stores the handle | 129 | /// Creates a new internal OpenGL resource and stores the handle |
| 96 | void Create() { | 130 | void Create() { |
| 97 | if (handle != 0) return; | 131 | if (handle != 0) |
| 132 | return; | ||
| 98 | glGenBuffers(1, &handle); | 133 | glGenBuffers(1, &handle); |
| 99 | } | 134 | } |
| 100 | 135 | ||
| 101 | /// Deletes the internal OpenGL resource | 136 | /// Deletes the internal OpenGL resource |
| 102 | void Release() { | 137 | void Release() { |
| 103 | if (handle == 0) return; | 138 | if (handle == 0) |
| 139 | return; | ||
| 104 | glDeleteBuffers(1, &handle); | 140 | glDeleteBuffers(1, &handle); |
| 105 | OpenGLState::ResetBuffer(handle); | 141 | OpenGLState::ResetBuffer(handle); |
| 106 | handle = 0; | 142 | handle = 0; |
| @@ -112,19 +148,28 @@ public: | |||
| 112 | class OGLVertexArray : private NonCopyable { | 148 | class OGLVertexArray : private NonCopyable { |
| 113 | public: | 149 | public: |
| 114 | OGLVertexArray() = default; | 150 | OGLVertexArray() = default; |
| 115 | OGLVertexArray(OGLVertexArray&& o) { std::swap(handle, o.handle); } | 151 | OGLVertexArray(OGLVertexArray&& o) { |
| 116 | ~OGLVertexArray() { Release(); } | 152 | std::swap(handle, o.handle); |
| 117 | OGLVertexArray& operator=(OGLVertexArray&& o) { std::swap(handle, o.handle); return *this; } | 153 | } |
| 154 | ~OGLVertexArray() { | ||
| 155 | Release(); | ||
| 156 | } | ||
| 157 | OGLVertexArray& operator=(OGLVertexArray&& o) { | ||
| 158 | std::swap(handle, o.handle); | ||
| 159 | return *this; | ||
| 160 | } | ||
| 118 | 161 | ||
| 119 | /// Creates a new internal OpenGL resource and stores the handle | 162 | /// Creates a new internal OpenGL resource and stores the handle |
| 120 | void Create() { | 163 | void Create() { |
| 121 | if (handle != 0) return; | 164 | if (handle != 0) |
| 165 | return; | ||
| 122 | glGenVertexArrays(1, &handle); | 166 | glGenVertexArrays(1, &handle); |
| 123 | } | 167 | } |
| 124 | 168 | ||
| 125 | /// Deletes the internal OpenGL resource | 169 | /// Deletes the internal OpenGL resource |
| 126 | void Release() { | 170 | void Release() { |
| 127 | if (handle == 0) return; | 171 | if (handle == 0) |
| 172 | return; | ||
| 128 | glDeleteVertexArrays(1, &handle); | 173 | glDeleteVertexArrays(1, &handle); |
| 129 | OpenGLState::ResetVertexArray(handle); | 174 | OpenGLState::ResetVertexArray(handle); |
| 130 | handle = 0; | 175 | handle = 0; |
| @@ -136,19 +181,28 @@ public: | |||
| 136 | class OGLFramebuffer : private NonCopyable { | 181 | class OGLFramebuffer : private NonCopyable { |
| 137 | public: | 182 | public: |
| 138 | OGLFramebuffer() = default; | 183 | OGLFramebuffer() = default; |
| 139 | OGLFramebuffer(OGLFramebuffer&& o) { std::swap(handle, o.handle); } | 184 | OGLFramebuffer(OGLFramebuffer&& o) { |
| 140 | ~OGLFramebuffer() { Release(); } | 185 | std::swap(handle, o.handle); |
| 141 | OGLFramebuffer& operator=(OGLFramebuffer&& o) { std::swap(handle, o.handle); return *this; } | 186 | } |
| 187 | ~OGLFramebuffer() { | ||
| 188 | Release(); | ||
| 189 | } | ||
| 190 | OGLFramebuffer& operator=(OGLFramebuffer&& o) { | ||
| 191 | std::swap(handle, o.handle); | ||
| 192 | return *this; | ||
| 193 | } | ||
| 142 | 194 | ||
| 143 | /// Creates a new internal OpenGL resource and stores the handle | 195 | /// Creates a new internal OpenGL resource and stores the handle |
| 144 | void Create() { | 196 | void Create() { |
| 145 | if (handle != 0) return; | 197 | if (handle != 0) |
| 198 | return; | ||
| 146 | glGenFramebuffers(1, &handle); | 199 | glGenFramebuffers(1, &handle); |
| 147 | } | 200 | } |
| 148 | 201 | ||
| 149 | /// Deletes the internal OpenGL resource | 202 | /// Deletes the internal OpenGL resource |
| 150 | void Release() { | 203 | void Release() { |
| 151 | if (handle == 0) return; | 204 | if (handle == 0) |
| 205 | return; | ||
| 152 | glDeleteFramebuffers(1, &handle); | 206 | glDeleteFramebuffers(1, &handle); |
| 153 | OpenGLState::ResetFramebuffer(handle); | 207 | OpenGLState::ResetFramebuffer(handle); |
| 154 | handle = 0; | 208 | 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 { | |||
| 21 | 21 | ||
| 22 | /// Detects if a TEV stage is configured to be skipped (to avoid generating unnecessary code) | 22 | /// Detects if a TEV stage is configured to be skipped (to avoid generating unnecessary code) |
| 23 | static bool IsPassThroughTevStage(const TevStageConfig& stage) { | 23 | static bool IsPassThroughTevStage(const TevStageConfig& stage) { |
| 24 | return (stage.color_op == TevStageConfig::Operation::Replace && | 24 | return (stage.color_op == TevStageConfig::Operation::Replace && |
| 25 | stage.alpha_op == TevStageConfig::Operation::Replace && | 25 | stage.alpha_op == TevStageConfig::Operation::Replace && |
| 26 | stage.color_source1 == TevStageConfig::Source::Previous && | 26 | stage.color_source1 == TevStageConfig::Source::Previous && |
| 27 | stage.alpha_source1 == TevStageConfig::Source::Previous && | 27 | stage.alpha_source1 == TevStageConfig::Source::Previous && |
| 28 | stage.color_modifier1 == TevStageConfig::ColorModifier::SourceColor && | 28 | stage.color_modifier1 == TevStageConfig::ColorModifier::SourceColor && |
| 29 | stage.alpha_modifier1 == TevStageConfig::AlphaModifier::SourceAlpha && | 29 | stage.alpha_modifier1 == TevStageConfig::AlphaModifier::SourceAlpha && |
| 30 | stage.GetColorMultiplier() == 1 && | 30 | stage.GetColorMultiplier() == 1 && stage.GetAlphaMultiplier() == 1); |
| 31 | stage.GetAlphaMultiplier() == 1); | ||
| 32 | } | 31 | } |
| 33 | 32 | ||
| 34 | /// Writes the specified TEV stage source component(s) | 33 | /// Writes the specified TEV stage source component(s) |
| 35 | static void AppendSource(std::string& out, const PicaShaderConfig& config, TevStageConfig::Source source, | 34 | static void AppendSource(std::string& out, const PicaShaderConfig& config, |
| 36 | const std::string& index_name) { | 35 | TevStageConfig::Source source, const std::string& index_name) { |
| 37 | const auto& state = config.state; | 36 | const auto& state = config.state; |
| 38 | using Source = TevStageConfig::Source; | 37 | using Source = TevStageConfig::Source; |
| 39 | switch (source) { | 38 | switch (source) { |
| @@ -48,7 +47,7 @@ static void AppendSource(std::string& out, const PicaShaderConfig& config, TevSt | |||
| 48 | break; | 47 | break; |
| 49 | case Source::Texture0: | 48 | case Source::Texture0: |
| 50 | // Only unit 0 respects the texturing type (according to 3DBrew) | 49 | // Only unit 0 respects the texturing type (according to 3DBrew) |
| 51 | switch(state.texture0_type) { | 50 | switch (state.texture0_type) { |
| 52 | case Pica::Regs::TextureConfig::Texture2D: | 51 | case Pica::Regs::TextureConfig::Texture2D: |
| 53 | out += "texture(tex[0], texcoord[0])"; | 52 | out += "texture(tex[0], texcoord[0])"; |
| 54 | break; | 53 | break; |
| @@ -57,7 +56,8 @@ static void AppendSource(std::string& out, const PicaShaderConfig& config, TevSt | |||
| 57 | break; | 56 | break; |
| 58 | default: | 57 | default: |
| 59 | out += "texture(tex[0], texcoord[0])"; | 58 | out += "texture(tex[0], texcoord[0])"; |
| 60 | LOG_CRITICAL(HW_GPU, "Unhandled texture type %x", static_cast<int>(state.texture0_type)); | 59 | LOG_CRITICAL(HW_GPU, "Unhandled texture type %x", |
| 60 | static_cast<int>(state.texture0_type)); | ||
| 61 | UNIMPLEMENTED(); | 61 | UNIMPLEMENTED(); |
| 62 | break; | 62 | break; |
| 63 | } | 63 | } |
| @@ -85,8 +85,9 @@ static void AppendSource(std::string& out, const PicaShaderConfig& config, TevSt | |||
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | /// Writes the color components to use for the specified TEV stage color modifier | 87 | /// Writes the color components to use for the specified TEV stage color modifier |
| 88 | static void AppendColorModifier(std::string& out, const PicaShaderConfig& config, TevStageConfig::ColorModifier modifier, | 88 | static void AppendColorModifier(std::string& out, const PicaShaderConfig& config, |
| 89 | TevStageConfig::Source source, const std::string& index_name) { | 89 | TevStageConfig::ColorModifier modifier, |
| 90 | TevStageConfig::Source source, const std::string& index_name) { | ||
| 90 | using ColorModifier = TevStageConfig::ColorModifier; | 91 | using ColorModifier = TevStageConfig::ColorModifier; |
| 91 | switch (modifier) { | 92 | switch (modifier) { |
| 92 | case ColorModifier::SourceColor: | 93 | case ColorModifier::SourceColor: |
| @@ -142,8 +143,9 @@ static void AppendColorModifier(std::string& out, const PicaShaderConfig& config | |||
| 142 | } | 143 | } |
| 143 | 144 | ||
| 144 | /// Writes the alpha component to use for the specified TEV stage alpha modifier | 145 | /// Writes the alpha component to use for the specified TEV stage alpha modifier |
| 145 | static void AppendAlphaModifier(std::string& out, const PicaShaderConfig& config, TevStageConfig::AlphaModifier modifier, | 146 | static void AppendAlphaModifier(std::string& out, const PicaShaderConfig& config, |
| 146 | TevStageConfig::Source source, const std::string& index_name) { | 147 | TevStageConfig::AlphaModifier modifier, |
| 148 | TevStageConfig::Source source, const std::string& index_name) { | ||
| 147 | using AlphaModifier = TevStageConfig::AlphaModifier; | 149 | using AlphaModifier = TevStageConfig::AlphaModifier; |
| 148 | switch (modifier) { | 150 | switch (modifier) { |
| 149 | case AlphaModifier::SourceAlpha: | 151 | case AlphaModifier::SourceAlpha: |
| @@ -191,7 +193,7 @@ static void AppendAlphaModifier(std::string& out, const PicaShaderConfig& config | |||
| 191 | 193 | ||
| 192 | /// Writes the combiner function for the color components for the specified TEV stage operation | 194 | /// Writes the combiner function for the color components for the specified TEV stage operation |
| 193 | static void AppendColorCombiner(std::string& out, TevStageConfig::Operation operation, | 195 | static void AppendColorCombiner(std::string& out, TevStageConfig::Operation operation, |
| 194 | const std::string& variable_name) { | 196 | const std::string& variable_name) { |
| 195 | out += "clamp("; | 197 | out += "clamp("; |
| 196 | using Operation = TevStageConfig::Operation; | 198 | using Operation = TevStageConfig::Operation; |
| 197 | switch (operation) { | 199 | switch (operation) { |
| @@ -208,8 +210,10 @@ static void AppendColorCombiner(std::string& out, TevStageConfig::Operation oper | |||
| 208 | out += variable_name + "[0] + " + variable_name + "[1] - vec3(0.5)"; | 210 | out += variable_name + "[0] + " + variable_name + "[1] - vec3(0.5)"; |
| 209 | break; | 211 | break; |
| 210 | case Operation::Lerp: | 212 | case Operation::Lerp: |
| 211 | // TODO(bunnei): Verify if HW actually does this per-component, otherwise we can just use builtin lerp | 213 | // TODO(bunnei): Verify if HW actually does this per-component, otherwise we can just use |
| 212 | out += variable_name + "[0] * " + variable_name + "[2] + " + variable_name + "[1] * (vec3(1.0) - " + variable_name + "[2])"; | 214 | // builtin lerp |
| 215 | out += variable_name + "[0] * " + variable_name + "[2] + " + variable_name + | ||
| 216 | "[1] * (vec3(1.0) - " + variable_name + "[2])"; | ||
| 213 | break; | 217 | break; |
| 214 | case Operation::Subtract: | 218 | case Operation::Subtract: |
| 215 | out += variable_name + "[0] - " + variable_name + "[1]"; | 219 | out += variable_name + "[0] - " + variable_name + "[1]"; |
| @@ -218,10 +222,12 @@ static void AppendColorCombiner(std::string& out, TevStageConfig::Operation oper | |||
| 218 | out += variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2]"; | 222 | out += variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2]"; |
| 219 | break; | 223 | break; |
| 220 | case Operation::AddThenMultiply: | 224 | case Operation::AddThenMultiply: |
| 221 | out += "min(" + variable_name + "[0] + " + variable_name + "[1], vec3(1.0)) * " + variable_name + "[2]"; | 225 | out += "min(" + variable_name + "[0] + " + variable_name + "[1], vec3(1.0)) * " + |
| 226 | variable_name + "[2]"; | ||
| 222 | break; | 227 | break; |
| 223 | case Operation::Dot3_RGB: | 228 | case Operation::Dot3_RGB: |
| 224 | out += "vec3(dot(" + variable_name + "[0] - vec3(0.5), " + variable_name + "[1] - vec3(0.5)) * 4.0)"; | 229 | out += "vec3(dot(" + variable_name + "[0] - vec3(0.5), " + variable_name + |
| 230 | "[1] - vec3(0.5)) * 4.0)"; | ||
| 225 | break; | 231 | break; |
| 226 | default: | 232 | default: |
| 227 | out += "vec3(0.0)"; | 233 | out += "vec3(0.0)"; |
| @@ -233,7 +239,7 @@ static void AppendColorCombiner(std::string& out, TevStageConfig::Operation oper | |||
| 233 | 239 | ||
| 234 | /// Writes the combiner function for the alpha component for the specified TEV stage operation | 240 | /// Writes the combiner function for the alpha component for the specified TEV stage operation |
| 235 | static void AppendAlphaCombiner(std::string& out, TevStageConfig::Operation operation, | 241 | static void AppendAlphaCombiner(std::string& out, TevStageConfig::Operation operation, |
| 236 | const std::string& variable_name) { | 242 | const std::string& variable_name) { |
| 237 | out += "clamp("; | 243 | out += "clamp("; |
| 238 | using Operation = TevStageConfig::Operation; | 244 | using Operation = TevStageConfig::Operation; |
| 239 | switch (operation) { | 245 | switch (operation) { |
| @@ -250,7 +256,8 @@ static void AppendAlphaCombiner(std::string& out, TevStageConfig::Operation oper | |||
| 250 | out += variable_name + "[0] + " + variable_name + "[1] - 0.5"; | 256 | out += variable_name + "[0] + " + variable_name + "[1] - 0.5"; |
| 251 | break; | 257 | break; |
| 252 | case Operation::Lerp: | 258 | case Operation::Lerp: |
| 253 | out += variable_name + "[0] * " + variable_name + "[2] + " + variable_name + "[1] * (1.0 - " + variable_name + "[2])"; | 259 | out += variable_name + "[0] * " + variable_name + "[2] + " + variable_name + |
| 260 | "[1] * (1.0 - " + variable_name + "[2])"; | ||
| 254 | break; | 261 | break; |
| 255 | case Operation::Subtract: | 262 | case Operation::Subtract: |
| 256 | out += variable_name + "[0] - " + variable_name + "[1]"; | 263 | out += variable_name + "[0] - " + variable_name + "[1]"; |
| @@ -259,7 +266,8 @@ static void AppendAlphaCombiner(std::string& out, TevStageConfig::Operation oper | |||
| 259 | out += variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2]"; | 266 | out += variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2]"; |
| 260 | break; | 267 | break; |
| 261 | case Operation::AddThenMultiply: | 268 | case Operation::AddThenMultiply: |
| 262 | out += "min(" + variable_name + "[0] + " + variable_name + "[1], 1.0) * " + variable_name + "[2]"; | 269 | out += "min(" + variable_name + "[0] + " + variable_name + "[1], 1.0) * " + variable_name + |
| 270 | "[2]"; | ||
| 263 | break; | 271 | break; |
| 264 | default: | 272 | default: |
| 265 | out += "0.0"; | 273 | out += "0.0"; |
| @@ -284,9 +292,10 @@ static void AppendAlphaTestCondition(std::string& out, Regs::CompareFunc func) { | |||
| 284 | case CompareFunc::LessThan: | 292 | case CompareFunc::LessThan: |
| 285 | case CompareFunc::LessThanOrEqual: | 293 | case CompareFunc::LessThanOrEqual: |
| 286 | case CompareFunc::GreaterThan: | 294 | case CompareFunc::GreaterThan: |
| 287 | case CompareFunc::GreaterThanOrEqual: | 295 | case CompareFunc::GreaterThanOrEqual: { |
| 288 | { | 296 | static const char* op[] = { |
| 289 | static const char* op[] = { "!=", "==", ">=", ">", "<=", "<", }; | 297 | "!=", "==", ">=", ">", "<=", "<", |
| 298 | }; | ||
| 290 | unsigned index = (unsigned)func - (unsigned)CompareFunc::Equal; | 299 | unsigned index = (unsigned)func - (unsigned)CompareFunc::Equal; |
| 291 | out += "int(last_tex_env_out.a * 255.0f) " + std::string(op[index]) + " alphatest_ref"; | 300 | out += "int(last_tex_env_out.a * 255.0f) " + std::string(op[index]) + " alphatest_ref"; |
| 292 | break; | 301 | break; |
| @@ -301,7 +310,8 @@ static void AppendAlphaTestCondition(std::string& out, Regs::CompareFunc func) { | |||
| 301 | 310 | ||
| 302 | /// Writes the code to emulate the specified TEV stage | 311 | /// Writes the code to emulate the specified TEV stage |
| 303 | static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsigned index) { | 312 | static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsigned index) { |
| 304 | const auto stage = static_cast<const Pica::Regs::TevStageConfig>(config.state.tev_stages[index]); | 313 | const auto stage = |
| 314 | static_cast<const Pica::Regs::TevStageConfig>(config.state.tev_stages[index]); | ||
| 305 | if (!IsPassThroughTevStage(stage)) { | 315 | if (!IsPassThroughTevStage(stage)) { |
| 306 | std::string index_name = std::to_string(index); | 316 | std::string index_name = std::to_string(index); |
| 307 | 317 | ||
| @@ -330,8 +340,12 @@ static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsi | |||
| 330 | out += ";\n"; | 340 | out += ";\n"; |
| 331 | 341 | ||
| 332 | out += "last_tex_env_out = vec4(" | 342 | out += "last_tex_env_out = vec4(" |
| 333 | "clamp(color_output_" + index_name + " * " + std::to_string(stage.GetColorMultiplier()) + ".0, vec3(0.0), vec3(1.0))," | 343 | "clamp(color_output_" + |
| 334 | "clamp(alpha_output_" + index_name + " * " + std::to_string(stage.GetAlphaMultiplier()) + ".0, 0.0, 1.0));\n"; | 344 | index_name + " * " + std::to_string(stage.GetColorMultiplier()) + |
| 345 | ".0, vec3(0.0), vec3(1.0))," | ||
| 346 | "clamp(alpha_output_" + | ||
| 347 | index_name + " * " + std::to_string(stage.GetAlphaMultiplier()) + | ||
| 348 | ".0, 0.0, 1.0));\n"; | ||
| 335 | } | 349 | } |
| 336 | 350 | ||
| 337 | out += "combiner_buffer = next_combiner_buffer;\n"; | 351 | out += "combiner_buffer = next_combiner_buffer;\n"; |
| @@ -355,13 +369,17 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | |||
| 355 | 369 | ||
| 356 | // Compute fragment normals | 370 | // Compute fragment normals |
| 357 | if (lighting.bump_mode == Pica::Regs::LightingBumpMode::NormalMap) { | 371 | if (lighting.bump_mode == Pica::Regs::LightingBumpMode::NormalMap) { |
| 358 | // Bump mapping is enabled using a normal map, read perturbation vector from the selected texture | 372 | // Bump mapping is enabled using a normal map, read perturbation vector from the selected |
| 373 | // texture | ||
| 359 | std::string bump_selector = std::to_string(lighting.bump_selector); | 374 | std::string bump_selector = std::to_string(lighting.bump_selector); |
| 360 | out += "vec3 surface_normal = 2.0 * texture(tex[" + bump_selector + "], texcoord[" + bump_selector + "]).rgb - 1.0;\n"; | 375 | out += "vec3 surface_normal = 2.0 * texture(tex[" + bump_selector + "], texcoord[" + |
| 376 | bump_selector + "]).rgb - 1.0;\n"; | ||
| 361 | 377 | ||
| 362 | // Recompute Z-component of perturbation if 'renorm' is enabled, this provides a higher precision result | 378 | // Recompute Z-component of perturbation if 'renorm' is enabled, this provides a higher |
| 379 | // precision result | ||
| 363 | if (lighting.bump_renorm) { | 380 | if (lighting.bump_renorm) { |
| 364 | std::string val = "(1.0 - (surface_normal.x*surface_normal.x + surface_normal.y*surface_normal.y))"; | 381 | std::string val = |
| 382 | "(1.0 - (surface_normal.x*surface_normal.x + surface_normal.y*surface_normal.y))"; | ||
| 365 | out += "surface_normal.z = sqrt(max(" + val + ", 0.0));\n"; | 383 | out += "surface_normal.z = sqrt(max(" + val + ", 0.0));\n"; |
| 366 | } | 384 | } |
| 367 | } else if (lighting.bump_mode == Pica::Regs::LightingBumpMode::TangentMap) { | 385 | } else if (lighting.bump_mode == Pica::Regs::LightingBumpMode::TangentMap) { |
| @@ -373,7 +391,8 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | |||
| 373 | out += "vec3 surface_normal = vec3(0.0, 0.0, 1.0);\n"; | 391 | out += "vec3 surface_normal = vec3(0.0, 0.0, 1.0);\n"; |
| 374 | } | 392 | } |
| 375 | 393 | ||
| 376 | // Rotate the surface-local normal by the interpolated normal quaternion to convert it to eyespace | 394 | // Rotate the surface-local normal by the interpolated normal quaternion to convert it to |
| 395 | // eyespace | ||
| 377 | out += "vec3 normal = normalize(quaternion_rotate(normquat, surface_normal));\n"; | 396 | out += "vec3 normal = normalize(quaternion_rotate(normquat, surface_normal));\n"; |
| 378 | 397 | ||
| 379 | // Gets the index into the specified lookup table for specular lighting | 398 | // Gets the index into the specified lookup table for specular lighting |
| @@ -406,12 +425,14 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | |||
| 406 | 425 | ||
| 407 | if (abs) { | 426 | if (abs) { |
| 408 | // LUT index is in the range of (0.0, 1.0) | 427 | // LUT index is in the range of (0.0, 1.0) |
| 409 | index = lighting.light[light_num].two_sided_diffuse ? "abs(" + index + ")" : "max(" + index + ", 0.f)"; | 428 | index = lighting.light[light_num].two_sided_diffuse ? "abs(" + index + ")" |
| 429 | : "max(" + index + ", 0.f)"; | ||
| 410 | return "(FLOAT_255 * clamp(" + index + ", 0.0, 1.0))"; | 430 | return "(FLOAT_255 * clamp(" + index + ", 0.0, 1.0))"; |
| 411 | } else { | 431 | } else { |
| 412 | // LUT index is in the range of (-1.0, 1.0) | 432 | // LUT index is in the range of (-1.0, 1.0) |
| 413 | index = "clamp(" + index + ", -1.0, 1.0)"; | 433 | index = "clamp(" + index + ", -1.0, 1.0)"; |
| 414 | return "(FLOAT_255 * ((" + index + " < 0) ? " + index + " + 2.0 : " + index + ") / 2.0)"; | 434 | return "(FLOAT_255 * ((" + index + " < 0) ? " + index + " + 2.0 : " + index + |
| 435 | ") / 2.0)"; | ||
| 415 | } | 436 | } |
| 416 | 437 | ||
| 417 | return std::string(); | 438 | return std::string(); |
| @@ -434,52 +455,74 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | |||
| 434 | else | 455 | else |
| 435 | out += "light_vector = normalize(" + light_src + ".position + view);\n"; | 456 | out += "light_vector = normalize(" + light_src + ".position + view);\n"; |
| 436 | 457 | ||
| 437 | // Compute dot product of light_vector and normal, adjust if lighting is one-sided or two-sided | 458 | // Compute dot product of light_vector and normal, adjust if lighting is one-sided or |
| 438 | std::string dot_product = light_config.two_sided_diffuse ? "abs(dot(light_vector, normal))" : "max(dot(light_vector, normal), 0.0)"; | 459 | // two-sided |
| 460 | std::string dot_product = light_config.two_sided_diffuse | ||
| 461 | ? "abs(dot(light_vector, normal))" | ||
| 462 | : "max(dot(light_vector, normal), 0.0)"; | ||
| 439 | 463 | ||
| 440 | // If enabled, compute distance attenuation value | 464 | // If enabled, compute distance attenuation value |
| 441 | std::string dist_atten = "1.0"; | 465 | std::string dist_atten = "1.0"; |
| 442 | if (light_config.dist_atten_enable) { | 466 | if (light_config.dist_atten_enable) { |
| 443 | std::string index = "(" + light_src + ".dist_atten_scale * length(-view - " + light_src + ".position) + " + light_src + ".dist_atten_bias)"; | 467 | std::string index = "(" + light_src + ".dist_atten_scale * length(-view - " + |
| 468 | light_src + ".position) + " + light_src + ".dist_atten_bias)"; | ||
| 444 | index = "((clamp(" + index + ", 0.0, FLOAT_255)))"; | 469 | index = "((clamp(" + index + ", 0.0, FLOAT_255)))"; |
| 445 | const unsigned lut_num = ((unsigned)Regs::LightingSampler::DistanceAttenuation + light_config.num); | 470 | const unsigned lut_num = |
| 471 | ((unsigned)Regs::LightingSampler::DistanceAttenuation + light_config.num); | ||
| 446 | dist_atten = GetLutValue((Regs::LightingSampler)lut_num, index); | 472 | dist_atten = GetLutValue((Regs::LightingSampler)lut_num, index); |
| 447 | } | 473 | } |
| 448 | 474 | ||
| 449 | // If enabled, clamp specular component if lighting result is negative | 475 | // If enabled, clamp specular component if lighting result is negative |
| 450 | std::string clamp_highlights = lighting.clamp_highlights ? "(dot(light_vector, normal) <= 0.0 ? 0.0 : 1.0)" : "1.0"; | 476 | std::string clamp_highlights = |
| 477 | lighting.clamp_highlights ? "(dot(light_vector, normal) <= 0.0 ? 0.0 : 1.0)" : "1.0"; | ||
| 451 | 478 | ||
| 452 | // Specular 0 component | 479 | // Specular 0 component |
| 453 | std::string d0_lut_value = "1.0"; | 480 | std::string d0_lut_value = "1.0"; |
| 454 | if (lighting.lut_d0.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::Distribution0)) { | 481 | if (lighting.lut_d0.enable && |
| 482 | Pica::Regs::IsLightingSamplerSupported(lighting.config, | ||
| 483 | Pica::Regs::LightingSampler::Distribution0)) { | ||
| 455 | // Lookup specular "distribution 0" LUT value | 484 | // Lookup specular "distribution 0" LUT value |
| 456 | std::string index = GetLutIndex(light_config.num, lighting.lut_d0.type, lighting.lut_d0.abs_input); | 485 | std::string index = |
| 457 | d0_lut_value = "(" + std::to_string(lighting.lut_d0.scale) + " * " + GetLutValue(Regs::LightingSampler::Distribution0, index) + ")"; | 486 | GetLutIndex(light_config.num, lighting.lut_d0.type, lighting.lut_d0.abs_input); |
| 487 | d0_lut_value = "(" + std::to_string(lighting.lut_d0.scale) + " * " + | ||
| 488 | GetLutValue(Regs::LightingSampler::Distribution0, index) + ")"; | ||
| 458 | } | 489 | } |
| 459 | std::string specular_0 = "(" + d0_lut_value + " * " + light_src + ".specular_0)"; | 490 | std::string specular_0 = "(" + d0_lut_value + " * " + light_src + ".specular_0)"; |
| 460 | 491 | ||
| 461 | // If enabled, lookup ReflectRed value, otherwise, 1.0 is used | 492 | // If enabled, lookup ReflectRed value, otherwise, 1.0 is used |
| 462 | if (lighting.lut_rr.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::ReflectRed)) { | 493 | if (lighting.lut_rr.enable && |
| 463 | std::string index = GetLutIndex(light_config.num, lighting.lut_rr.type, lighting.lut_rr.abs_input); | 494 | Pica::Regs::IsLightingSamplerSupported(lighting.config, |
| 464 | std::string value = "(" + std::to_string(lighting.lut_rr.scale) + " * " + GetLutValue(Regs::LightingSampler::ReflectRed, index) + ")"; | 495 | Pica::Regs::LightingSampler::ReflectRed)) { |
| 496 | std::string index = | ||
| 497 | GetLutIndex(light_config.num, lighting.lut_rr.type, lighting.lut_rr.abs_input); | ||
| 498 | std::string value = "(" + std::to_string(lighting.lut_rr.scale) + " * " + | ||
| 499 | GetLutValue(Regs::LightingSampler::ReflectRed, index) + ")"; | ||
| 465 | out += "refl_value.r = " + value + ";\n"; | 500 | out += "refl_value.r = " + value + ";\n"; |
| 466 | } else { | 501 | } else { |
| 467 | out += "refl_value.r = 1.0;\n"; | 502 | out += "refl_value.r = 1.0;\n"; |
| 468 | } | 503 | } |
| 469 | 504 | ||
| 470 | // If enabled, lookup ReflectGreen value, otherwise, ReflectRed value is used | 505 | // If enabled, lookup ReflectGreen value, otherwise, ReflectRed value is used |
| 471 | if (lighting.lut_rg.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::ReflectGreen)) { | 506 | if (lighting.lut_rg.enable && |
| 472 | std::string index = GetLutIndex(light_config.num, lighting.lut_rg.type, lighting.lut_rg.abs_input); | 507 | Pica::Regs::IsLightingSamplerSupported(lighting.config, |
| 473 | std::string value = "(" + std::to_string(lighting.lut_rg.scale) + " * " + GetLutValue(Regs::LightingSampler::ReflectGreen, index) + ")"; | 508 | Pica::Regs::LightingSampler::ReflectGreen)) { |
| 509 | std::string index = | ||
| 510 | GetLutIndex(light_config.num, lighting.lut_rg.type, lighting.lut_rg.abs_input); | ||
| 511 | std::string value = "(" + std::to_string(lighting.lut_rg.scale) + " * " + | ||
| 512 | GetLutValue(Regs::LightingSampler::ReflectGreen, index) + ")"; | ||
| 474 | out += "refl_value.g = " + value + ";\n"; | 513 | out += "refl_value.g = " + value + ";\n"; |
| 475 | } else { | 514 | } else { |
| 476 | out += "refl_value.g = refl_value.r;\n"; | 515 | out += "refl_value.g = refl_value.r;\n"; |
| 477 | } | 516 | } |
| 478 | 517 | ||
| 479 | // If enabled, lookup ReflectBlue value, otherwise, ReflectRed value is used | 518 | // If enabled, lookup ReflectBlue value, otherwise, ReflectRed value is used |
| 480 | if (lighting.lut_rb.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::ReflectBlue)) { | 519 | if (lighting.lut_rb.enable && |
| 481 | std::string index = GetLutIndex(light_config.num, lighting.lut_rb.type, lighting.lut_rb.abs_input); | 520 | Pica::Regs::IsLightingSamplerSupported(lighting.config, |
| 482 | std::string value = "(" + std::to_string(lighting.lut_rb.scale) + " * " + GetLutValue(Regs::LightingSampler::ReflectBlue, index) + ")"; | 521 | Pica::Regs::LightingSampler::ReflectBlue)) { |
| 522 | std::string index = | ||
| 523 | GetLutIndex(light_config.num, lighting.lut_rb.type, lighting.lut_rb.abs_input); | ||
| 524 | std::string value = "(" + std::to_string(lighting.lut_rb.scale) + " * " + | ||
| 525 | GetLutValue(Regs::LightingSampler::ReflectBlue, index) + ")"; | ||
| 483 | out += "refl_value.b = " + value + ";\n"; | 526 | out += "refl_value.b = " + value + ";\n"; |
| 484 | } else { | 527 | } else { |
| 485 | out += "refl_value.b = refl_value.r;\n"; | 528 | out += "refl_value.b = refl_value.r;\n"; |
| @@ -487,18 +530,26 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | |||
| 487 | 530 | ||
| 488 | // Specular 1 component | 531 | // Specular 1 component |
| 489 | std::string d1_lut_value = "1.0"; | 532 | std::string d1_lut_value = "1.0"; |
| 490 | if (lighting.lut_d1.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::Distribution1)) { | 533 | if (lighting.lut_d1.enable && |
| 534 | Pica::Regs::IsLightingSamplerSupported(lighting.config, | ||
| 535 | Pica::Regs::LightingSampler::Distribution1)) { | ||
| 491 | // Lookup specular "distribution 1" LUT value | 536 | // Lookup specular "distribution 1" LUT value |
| 492 | std::string index = GetLutIndex(light_config.num, lighting.lut_d1.type, lighting.lut_d1.abs_input); | 537 | std::string index = |
| 493 | d1_lut_value = "(" + std::to_string(lighting.lut_d1.scale) + " * " + GetLutValue(Regs::LightingSampler::Distribution1, index) + ")"; | 538 | GetLutIndex(light_config.num, lighting.lut_d1.type, lighting.lut_d1.abs_input); |
| 539 | d1_lut_value = "(" + std::to_string(lighting.lut_d1.scale) + " * " + | ||
| 540 | GetLutValue(Regs::LightingSampler::Distribution1, index) + ")"; | ||
| 494 | } | 541 | } |
| 495 | std::string specular_1 = "(" + d1_lut_value + " * refl_value * " + light_src + ".specular_1)"; | 542 | std::string specular_1 = |
| 543 | "(" + d1_lut_value + " * refl_value * " + light_src + ".specular_1)"; | ||
| 496 | 544 | ||
| 497 | // Fresnel | 545 | // Fresnel |
| 498 | if (lighting.lut_fr.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::Fresnel)) { | 546 | if (lighting.lut_fr.enable && Pica::Regs::IsLightingSamplerSupported( |
| 547 | lighting.config, Pica::Regs::LightingSampler::Fresnel)) { | ||
| 499 | // Lookup fresnel LUT value | 548 | // Lookup fresnel LUT value |
| 500 | std::string index = GetLutIndex(light_config.num, lighting.lut_fr.type, lighting.lut_fr.abs_input); | 549 | std::string index = |
| 501 | std::string value = "(" + std::to_string(lighting.lut_fr.scale) + " * " + GetLutValue(Regs::LightingSampler::Fresnel, index) + ")"; | 550 | GetLutIndex(light_config.num, lighting.lut_fr.type, lighting.lut_fr.abs_input); |
| 551 | std::string value = "(" + std::to_string(lighting.lut_fr.scale) + " * " + | ||
| 552 | GetLutValue(Regs::LightingSampler::Fresnel, index) + ")"; | ||
| 502 | 553 | ||
| 503 | // Enabled for difffuse lighting alpha component | 554 | // Enabled for difffuse lighting alpha component |
| 504 | if (lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::PrimaryAlpha || | 555 | if (lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::PrimaryAlpha || |
| @@ -512,10 +563,12 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | |||
| 512 | } | 563 | } |
| 513 | 564 | ||
| 514 | // Compute primary fragment color (diffuse lighting) function | 565 | // Compute primary fragment color (diffuse lighting) function |
| 515 | out += "diffuse_sum.rgb += ((" + light_src + ".diffuse * " + dot_product + ") + " + light_src + ".ambient) * " + dist_atten + ";\n"; | 566 | out += "diffuse_sum.rgb += ((" + light_src + ".diffuse * " + dot_product + ") + " + |
| 567 | light_src + ".ambient) * " + dist_atten + ";\n"; | ||
| 516 | 568 | ||
| 517 | // Compute secondary fragment color (specular lighting) function | 569 | // Compute secondary fragment color (specular lighting) function |
| 518 | out += "specular_sum.rgb += (" + specular_0 + " + " + specular_1 + ") * " + clamp_highlights + " * " + dist_atten + ";\n"; | 570 | out += "specular_sum.rgb += (" + specular_0 + " + " + specular_1 + ") * " + |
| 571 | clamp_highlights + " * " + dist_atten + ";\n"; | ||
| 519 | } | 572 | } |
| 520 | 573 | ||
| 521 | // Sum final lighting result | 574 | // Sum final lighting result |
| @@ -598,9 +651,9 @@ vec4 secondary_fragment_color = vec4(0.0); | |||
| 598 | out += "!"; | 651 | out += "!"; |
| 599 | // x2,y2 have +1 added to cover the entire pixel area | 652 | // x2,y2 have +1 added to cover the entire pixel area |
| 600 | out += "(gl_FragCoord.x >= scissor_x1 * framebuffer_scale.x && " | 653 | out += "(gl_FragCoord.x >= scissor_x1 * framebuffer_scale.x && " |
| 601 | "gl_FragCoord.y >= scissor_y1 * framebuffer_scale.y && " | 654 | "gl_FragCoord.y >= scissor_y1 * framebuffer_scale.y && " |
| 602 | "gl_FragCoord.x < (scissor_x2 + 1) * framebuffer_scale.x && " | 655 | "gl_FragCoord.x < (scissor_x2 + 1) * framebuffer_scale.x && " |
| 603 | "gl_FragCoord.y < (scissor_y2 + 1) * framebuffer_scale.y)) discard;\n"; | 656 | "gl_FragCoord.y < (scissor_y2 + 1) * framebuffer_scale.y)) discard;\n"; |
| 604 | } | 657 | } |
| 605 | 658 | ||
| 606 | out += "float z_over_w = 1.0 - gl_FragCoord.z * 2.0;\n"; | 659 | out += "float z_over_w = 1.0 - gl_FragCoord.z * 2.0;\n"; |
| @@ -638,9 +691,11 @@ vec4 secondary_fragment_color = vec4(0.0); | |||
| 638 | out += "float fog_i = clamp(floor(fog_index), 0.0, 127.0);\n"; | 691 | out += "float fog_i = clamp(floor(fog_index), 0.0, 127.0);\n"; |
| 639 | out += "float fog_f = fog_index - fog_i;\n"; | 692 | out += "float fog_f = fog_index - fog_i;\n"; |
| 640 | out += "uint fog_lut_entry = texelFetch(fog_lut, int(fog_i), 0).r;\n"; | 693 | out += "uint fog_lut_entry = texelFetch(fog_lut, int(fog_i), 0).r;\n"; |
| 641 | out += "float fog_lut_entry_difference = float(int((fog_lut_entry & 0x1FFFU) << 19U) >> 19);\n"; // Extract signed difference | 694 | out += "float fog_lut_entry_difference = float(int((fog_lut_entry & 0x1FFFU) << 19U) >> " |
| 695 | "19);\n"; // Extract signed difference | ||
| 642 | out += "float fog_lut_entry_value = float((fog_lut_entry >> 13U) & 0x7FFU);\n"; | 696 | out += "float fog_lut_entry_value = float((fog_lut_entry >> 13U) & 0x7FFU);\n"; |
| 643 | out += "float fog_factor = (fog_lut_entry_value + fog_lut_entry_difference * fog_f) / 2047.0;\n"; | 697 | out += "float fog_factor = (fog_lut_entry_value + fog_lut_entry_difference * fog_f) / " |
| 698 | "2047.0;\n"; | ||
| 644 | out += "fog_factor = clamp(fog_factor, 0.0, 1.0);\n"; | 699 | out += "fog_factor = clamp(fog_factor, 0.0, 1.0);\n"; |
| 645 | 700 | ||
| 646 | // Blend the fog | 701 | // Blend the fog |
| @@ -658,14 +713,20 @@ vec4 secondary_fragment_color = vec4(0.0); | |||
| 658 | std::string GenerateVertexShader() { | 713 | std::string GenerateVertexShader() { |
| 659 | std::string out = "#version 330 core\n"; | 714 | std::string out = "#version 330 core\n"; |
| 660 | 715 | ||
| 661 | out += "layout(location = " + std::to_string((int)ATTRIBUTE_POSITION) + ") in vec4 vert_position;\n"; | 716 | out += "layout(location = " + std::to_string((int)ATTRIBUTE_POSITION) + |
| 662 | out += "layout(location = " + std::to_string((int)ATTRIBUTE_COLOR) + ") in vec4 vert_color;\n"; | 717 | ") in vec4 vert_position;\n"; |
| 663 | out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD0) + ") in vec2 vert_texcoord0;\n"; | 718 | out += "layout(location = " + std::to_string((int)ATTRIBUTE_COLOR) + ") in vec4 vert_color;\n"; |
| 664 | out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD1) + ") in vec2 vert_texcoord1;\n"; | 719 | out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD0) + |
| 665 | out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD2) + ") in vec2 vert_texcoord2;\n"; | 720 | ") in vec2 vert_texcoord0;\n"; |
| 666 | out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD0_W) + ") in float vert_texcoord0_w;\n"; | 721 | out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD1) + |
| 667 | out += "layout(location = " + std::to_string((int)ATTRIBUTE_NORMQUAT) + ") in vec4 vert_normquat;\n"; | 722 | ") in vec2 vert_texcoord1;\n"; |
| 668 | out += "layout(location = " + std::to_string((int)ATTRIBUTE_VIEW) + ") in vec3 vert_view;\n"; | 723 | out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD2) + |
| 724 | ") in vec2 vert_texcoord2;\n"; | ||
| 725 | out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD0_W) + | ||
| 726 | ") in float vert_texcoord0_w;\n"; | ||
| 727 | out += "layout(location = " + std::to_string((int)ATTRIBUTE_NORMQUAT) + | ||
| 728 | ") in vec4 vert_normquat;\n"; | ||
| 729 | out += "layout(location = " + std::to_string((int)ATTRIBUTE_VIEW) + ") in vec3 vert_view;\n"; | ||
| 669 | 730 | ||
| 670 | out += R"( | 731 | out += R"( |
| 671 | out vec4 primary_color; | 732 | 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) { | |||
| 56 | if (result) { | 56 | if (result) { |
| 57 | LOG_DEBUG(Render_OpenGL, "%s", &fragment_shader_error[0]); | 57 | LOG_DEBUG(Render_OpenGL, "%s", &fragment_shader_error[0]); |
| 58 | } else { | 58 | } else { |
| 59 | LOG_ERROR(Render_OpenGL, "Error compiling fragment shader:\n%s", &fragment_shader_error[0]); | 59 | LOG_ERROR(Render_OpenGL, "Error compiling fragment shader:\n%s", |
| 60 | &fragment_shader_error[0]); | ||
| 60 | } | 61 | } |
| 61 | } | 62 | } |
| 62 | 63 | ||
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 { | |||
| 106 | 106 | ||
| 107 | // Color mask | 107 | // Color mask |
| 108 | if (color_mask.red_enabled != cur_state.color_mask.red_enabled || | 108 | if (color_mask.red_enabled != cur_state.color_mask.red_enabled || |
| 109 | color_mask.green_enabled != cur_state.color_mask.green_enabled || | 109 | color_mask.green_enabled != cur_state.color_mask.green_enabled || |
| 110 | color_mask.blue_enabled != cur_state.color_mask.blue_enabled || | 110 | color_mask.blue_enabled != cur_state.color_mask.blue_enabled || |
| 111 | color_mask.alpha_enabled != cur_state.color_mask.alpha_enabled) { | 111 | color_mask.alpha_enabled != cur_state.color_mask.alpha_enabled) { |
| 112 | glColorMask(color_mask.red_enabled, color_mask.green_enabled, | 112 | glColorMask(color_mask.red_enabled, color_mask.green_enabled, color_mask.blue_enabled, |
| 113 | color_mask.blue_enabled, color_mask.alpha_enabled); | 113 | color_mask.alpha_enabled); |
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | // Stencil test | 116 | // Stencil test |
| @@ -123,15 +123,16 @@ void OpenGLState::Apply() const { | |||
| 123 | } | 123 | } |
| 124 | 124 | ||
| 125 | if (stencil.test_func != cur_state.stencil.test_func || | 125 | if (stencil.test_func != cur_state.stencil.test_func || |
| 126 | stencil.test_ref != cur_state.stencil.test_ref || | 126 | stencil.test_ref != cur_state.stencil.test_ref || |
| 127 | stencil.test_mask != cur_state.stencil.test_mask) { | 127 | stencil.test_mask != cur_state.stencil.test_mask) { |
| 128 | glStencilFunc(stencil.test_func, stencil.test_ref, stencil.test_mask); | 128 | glStencilFunc(stencil.test_func, stencil.test_ref, stencil.test_mask); |
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | if (stencil.action_depth_fail != cur_state.stencil.action_depth_fail || | 131 | if (stencil.action_depth_fail != cur_state.stencil.action_depth_fail || |
| 132 | stencil.action_depth_pass != cur_state.stencil.action_depth_pass || | 132 | stencil.action_depth_pass != cur_state.stencil.action_depth_pass || |
| 133 | stencil.action_stencil_fail != cur_state.stencil.action_stencil_fail) { | 133 | stencil.action_stencil_fail != cur_state.stencil.action_stencil_fail) { |
| 134 | glStencilOp(stencil.action_stencil_fail, stencil.action_depth_fail, stencil.action_depth_pass); | 134 | glStencilOp(stencil.action_stencil_fail, stencil.action_depth_fail, |
| 135 | stencil.action_depth_pass); | ||
| 135 | } | 136 | } |
| 136 | 137 | ||
| 137 | // Stencil mask | 138 | // Stencil mask |
| @@ -154,23 +155,22 @@ void OpenGLState::Apply() const { | |||
| 154 | } | 155 | } |
| 155 | 156 | ||
| 156 | if (blend.color.red != cur_state.blend.color.red || | 157 | if (blend.color.red != cur_state.blend.color.red || |
| 157 | blend.color.green != cur_state.blend.color.green || | 158 | blend.color.green != cur_state.blend.color.green || |
| 158 | blend.color.blue != cur_state.blend.color.blue || | 159 | blend.color.blue != cur_state.blend.color.blue || |
| 159 | blend.color.alpha != cur_state.blend.color.alpha) { | 160 | blend.color.alpha != cur_state.blend.color.alpha) { |
| 160 | glBlendColor(blend.color.red, blend.color.green, | 161 | glBlendColor(blend.color.red, blend.color.green, blend.color.blue, blend.color.alpha); |
| 161 | blend.color.blue, blend.color.alpha); | ||
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | if (blend.src_rgb_func != cur_state.blend.src_rgb_func || | 164 | if (blend.src_rgb_func != cur_state.blend.src_rgb_func || |
| 165 | blend.dst_rgb_func != cur_state.blend.dst_rgb_func || | 165 | blend.dst_rgb_func != cur_state.blend.dst_rgb_func || |
| 166 | blend.src_a_func != cur_state.blend.src_a_func || | 166 | blend.src_a_func != cur_state.blend.src_a_func || |
| 167 | blend.dst_a_func != cur_state.blend.dst_a_func) { | 167 | blend.dst_a_func != cur_state.blend.dst_a_func) { |
| 168 | glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, | 168 | glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, blend.src_a_func, |
| 169 | blend.src_a_func, blend.dst_a_func); | 169 | blend.dst_a_func); |
| 170 | } | 170 | } |
| 171 | 171 | ||
| 172 | if (blend.rgb_equation != cur_state.blend.rgb_equation || | 172 | if (blend.rgb_equation != cur_state.blend.rgb_equation || |
| 173 | blend.a_equation != cur_state.blend.a_equation) { | 173 | blend.a_equation != cur_state.blend.a_equation) { |
| 174 | glBlendEquationSeparate(blend.rgb_equation, blend.a_equation); | 174 | glBlendEquationSeparate(blend.rgb_equation, blend.a_equation); |
| 175 | } | 175 | } |
| 176 | 176 | ||
| @@ -237,8 +237,11 @@ void OpenGLState::Apply() const { | |||
| 237 | GLenum OpenGLState::CheckFBStatus(GLenum target) { | 237 | GLenum OpenGLState::CheckFBStatus(GLenum target) { |
| 238 | GLenum fb_status = glCheckFramebufferStatus(target); | 238 | GLenum fb_status = glCheckFramebufferStatus(target); |
| 239 | if (fb_status != GL_FRAMEBUFFER_COMPLETE) { | 239 | if (fb_status != GL_FRAMEBUFFER_COMPLETE) { |
| 240 | const char* fb_description = (target == GL_READ_FRAMEBUFFER ? "READ" : (target == GL_DRAW_FRAMEBUFFER ? "DRAW" : "UNK")); | 240 | const char* fb_description = |
| 241 | LOG_CRITICAL(Render_OpenGL, "OpenGL %s framebuffer check failed, status %X", fb_description, fb_status); | 241 | (target == GL_READ_FRAMEBUFFER ? "READ" |
| 242 | : (target == GL_DRAW_FRAMEBUFFER ? "DRAW" : "UNK")); | ||
| 243 | LOG_CRITICAL(Render_OpenGL, "OpenGL %s framebuffer check failed, status %X", fb_description, | ||
| 244 | fb_status); | ||
| 242 | } | 245 | } |
| 243 | 246 | ||
| 244 | return fb_status; | 247 | 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 @@ | |||
| 9 | class OpenGLState { | 9 | class OpenGLState { |
| 10 | public: | 10 | public: |
| 11 | struct { | 11 | struct { |
| 12 | bool enabled; // GL_CULL_FACE | 12 | bool enabled; // GL_CULL_FACE |
| 13 | GLenum mode; // GL_CULL_FACE_MODE | 13 | GLenum mode; // GL_CULL_FACE_MODE |
| 14 | GLenum front_face; // GL_FRONT_FACE | 14 | GLenum front_face; // GL_FRONT_FACE |
| 15 | } cull; | 15 | } cull; |
| 16 | 16 | ||
| 17 | struct { | 17 | struct { |
| 18 | bool test_enabled; // GL_DEPTH_TEST | 18 | bool test_enabled; // GL_DEPTH_TEST |
| 19 | GLenum test_func; // GL_DEPTH_FUNC | 19 | GLenum test_func; // GL_DEPTH_FUNC |
| 20 | GLboolean write_mask; // GL_DEPTH_WRITEMASK | 20 | GLboolean write_mask; // GL_DEPTH_WRITEMASK |
| 21 | } depth; | 21 | } depth; |
| 22 | 22 | ||
| @@ -28,24 +28,24 @@ public: | |||
| 28 | } color_mask; // GL_COLOR_WRITEMASK | 28 | } color_mask; // GL_COLOR_WRITEMASK |
| 29 | 29 | ||
| 30 | struct { | 30 | struct { |
| 31 | bool test_enabled; // GL_STENCIL_TEST | 31 | bool test_enabled; // GL_STENCIL_TEST |
| 32 | GLenum test_func; // GL_STENCIL_FUNC | 32 | GLenum test_func; // GL_STENCIL_FUNC |
| 33 | GLint test_ref; // GL_STENCIL_REF | 33 | GLint test_ref; // GL_STENCIL_REF |
| 34 | GLuint test_mask; // GL_STENCIL_VALUE_MASK | 34 | GLuint test_mask; // GL_STENCIL_VALUE_MASK |
| 35 | GLuint write_mask; // GL_STENCIL_WRITEMASK | 35 | GLuint write_mask; // GL_STENCIL_WRITEMASK |
| 36 | GLenum action_stencil_fail; // GL_STENCIL_FAIL | 36 | GLenum action_stencil_fail; // GL_STENCIL_FAIL |
| 37 | GLenum action_depth_fail; // GL_STENCIL_PASS_DEPTH_FAIL | 37 | GLenum action_depth_fail; // GL_STENCIL_PASS_DEPTH_FAIL |
| 38 | GLenum action_depth_pass; // GL_STENCIL_PASS_DEPTH_PASS | 38 | GLenum action_depth_pass; // GL_STENCIL_PASS_DEPTH_PASS |
| 39 | } stencil; | 39 | } stencil; |
| 40 | 40 | ||
| 41 | struct { | 41 | struct { |
| 42 | bool enabled; // GL_BLEND | 42 | bool enabled; // GL_BLEND |
| 43 | GLenum rgb_equation; // GL_BLEND_EQUATION_RGB | 43 | GLenum rgb_equation; // GL_BLEND_EQUATION_RGB |
| 44 | GLenum a_equation; // GL_BLEND_EQUATION_ALPHA | 44 | GLenum a_equation; // GL_BLEND_EQUATION_ALPHA |
| 45 | GLenum src_rgb_func; // GL_BLEND_SRC_RGB | 45 | GLenum src_rgb_func; // GL_BLEND_SRC_RGB |
| 46 | GLenum dst_rgb_func; // GL_BLEND_DST_RGB | 46 | GLenum dst_rgb_func; // GL_BLEND_DST_RGB |
| 47 | GLenum src_a_func; // GL_BLEND_SRC_ALPHA | 47 | GLenum src_a_func; // GL_BLEND_SRC_ALPHA |
| 48 | GLenum dst_a_func; // GL_BLEND_DST_ALPHA | 48 | GLenum dst_a_func; // GL_BLEND_DST_ALPHA |
| 49 | 49 | ||
| 50 | struct { | 50 | struct { |
| 51 | GLclampf red; | 51 | GLclampf red; |
| @@ -60,7 +60,7 @@ public: | |||
| 60 | // 3 texture units - one for each that is used in PICA fragment shader emulation | 60 | // 3 texture units - one for each that is used in PICA fragment shader emulation |
| 61 | struct { | 61 | struct { |
| 62 | GLuint texture_2d; // GL_TEXTURE_BINDING_2D | 62 | GLuint texture_2d; // GL_TEXTURE_BINDING_2D |
| 63 | GLuint sampler; // GL_SAMPLER_BINDING | 63 | GLuint sampler; // GL_SAMPLER_BINDING |
| 64 | } texture_units[3]; | 64 | } texture_units[3]; |
| 65 | 65 | ||
| 66 | struct { | 66 | struct { |
| @@ -74,10 +74,10 @@ public: | |||
| 74 | struct { | 74 | struct { |
| 75 | GLuint read_framebuffer; // GL_READ_FRAMEBUFFER_BINDING | 75 | GLuint read_framebuffer; // GL_READ_FRAMEBUFFER_BINDING |
| 76 | GLuint draw_framebuffer; // GL_DRAW_FRAMEBUFFER_BINDING | 76 | GLuint draw_framebuffer; // GL_DRAW_FRAMEBUFFER_BINDING |
| 77 | GLuint vertex_array; // GL_VERTEX_ARRAY_BINDING | 77 | GLuint vertex_array; // GL_VERTEX_ARRAY_BINDING |
| 78 | GLuint vertex_buffer; // GL_ARRAY_BUFFER_BINDING | 78 | GLuint vertex_buffer; // GL_ARRAY_BUFFER_BINDING |
| 79 | GLuint uniform_buffer; // GL_UNIFORM_BUFFER_BINDING | 79 | GLuint uniform_buffer; // GL_UNIFORM_BUFFER_BINDING |
| 80 | GLuint shader_program; // GL_CURRENT_PROGRAM | 80 | GLuint shader_program; // GL_CURRENT_PROGRAM |
| 81 | } draw; | 81 | } draw; |
| 82 | 82 | ||
| 83 | OpenGLState(); | 83 | 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 { | |||
| 25 | 25 | ||
| 26 | inline GLenum TextureFilterMode(Pica::Regs::TextureConfig::TextureFilter mode) { | 26 | inline GLenum TextureFilterMode(Pica::Regs::TextureConfig::TextureFilter mode) { |
| 27 | static const GLenum filter_mode_table[] = { | 27 | static const GLenum filter_mode_table[] = { |
| 28 | GL_NEAREST, // TextureFilter::Nearest | 28 | GL_NEAREST, // TextureFilter::Nearest |
| 29 | GL_LINEAR // TextureFilter::Linear | 29 | GL_LINEAR // TextureFilter::Linear |
| 30 | }; | 30 | }; |
| 31 | 31 | ||
| 32 | // Range check table for input | 32 | // Range check table for input |
| @@ -52,10 +52,10 @@ inline GLenum TextureFilterMode(Pica::Regs::TextureConfig::TextureFilter mode) { | |||
| 52 | 52 | ||
| 53 | inline GLenum WrapMode(Pica::Regs::TextureConfig::WrapMode mode) { | 53 | inline GLenum WrapMode(Pica::Regs::TextureConfig::WrapMode mode) { |
| 54 | static const GLenum wrap_mode_table[] = { | 54 | static const GLenum wrap_mode_table[] = { |
| 55 | GL_CLAMP_TO_EDGE, // WrapMode::ClampToEdge | 55 | GL_CLAMP_TO_EDGE, // WrapMode::ClampToEdge |
| 56 | GL_CLAMP_TO_BORDER,// WrapMode::ClampToBorder | 56 | GL_CLAMP_TO_BORDER, // WrapMode::ClampToBorder |
| 57 | GL_REPEAT, // WrapMode::Repeat | 57 | GL_REPEAT, // WrapMode::Repeat |
| 58 | GL_MIRRORED_REPEAT // WrapMode::MirroredRepeat | 58 | GL_MIRRORED_REPEAT // WrapMode::MirroredRepeat |
| 59 | }; | 59 | }; |
| 60 | 60 | ||
| 61 | // Range check table for input | 61 | // Range check table for input |
| @@ -131,22 +131,22 @@ inline GLenum BlendFunc(Pica::Regs::BlendFactor factor) { | |||
| 131 | 131 | ||
| 132 | inline GLenum LogicOp(Pica::Regs::LogicOp op) { | 132 | inline GLenum LogicOp(Pica::Regs::LogicOp op) { |
| 133 | static const GLenum logic_op_table[] = { | 133 | static const GLenum logic_op_table[] = { |
| 134 | GL_CLEAR, // Clear | 134 | GL_CLEAR, // Clear |
| 135 | GL_AND, // And | 135 | GL_AND, // And |
| 136 | GL_AND_REVERSE, // AndReverse | 136 | GL_AND_REVERSE, // AndReverse |
| 137 | GL_COPY, // Copy | 137 | GL_COPY, // Copy |
| 138 | GL_SET, // Set | 138 | GL_SET, // Set |
| 139 | GL_COPY_INVERTED, // CopyInverted | 139 | GL_COPY_INVERTED, // CopyInverted |
| 140 | GL_NOOP, // NoOp | 140 | GL_NOOP, // NoOp |
| 141 | GL_INVERT, // Invert | 141 | GL_INVERT, // Invert |
| 142 | GL_NAND, // Nand | 142 | GL_NAND, // Nand |
| 143 | GL_OR, // Or | 143 | GL_OR, // Or |
| 144 | GL_NOR, // Nor | 144 | GL_NOR, // Nor |
| 145 | GL_XOR, // Xor | 145 | GL_XOR, // Xor |
| 146 | GL_EQUIV, // Equiv | 146 | GL_EQUIV, // Equiv |
| 147 | GL_AND_INVERTED, // AndInverted | 147 | GL_AND_INVERTED, // AndInverted |
| 148 | GL_OR_REVERSE, // OrReverse | 148 | GL_OR_REVERSE, // OrReverse |
| 149 | GL_OR_INVERTED, // OrInverted | 149 | GL_OR_INVERTED, // OrInverted |
| 150 | }; | 150 | }; |
| 151 | 151 | ||
| 152 | // Range check table for input | 152 | // Range check table for input |
| @@ -185,14 +185,14 @@ inline GLenum CompareFunc(Pica::Regs::CompareFunc func) { | |||
| 185 | 185 | ||
| 186 | inline GLenum StencilOp(Pica::Regs::StencilAction action) { | 186 | inline GLenum StencilOp(Pica::Regs::StencilAction action) { |
| 187 | static const GLenum stencil_op_table[] = { | 187 | static const GLenum stencil_op_table[] = { |
| 188 | GL_KEEP, // StencilAction::Keep | 188 | GL_KEEP, // StencilAction::Keep |
| 189 | GL_ZERO, // StencilAction::Zero | 189 | GL_ZERO, // StencilAction::Zero |
| 190 | GL_REPLACE, // StencilAction::Replace | 190 | GL_REPLACE, // StencilAction::Replace |
| 191 | GL_INCR, // StencilAction::Increment | 191 | GL_INCR, // StencilAction::Increment |
| 192 | GL_DECR, // StencilAction::Decrement | 192 | GL_DECR, // StencilAction::Decrement |
| 193 | GL_INVERT, // StencilAction::Invert | 193 | GL_INVERT, // StencilAction::Invert |
| 194 | GL_INCR_WRAP, // StencilAction::IncrementWrap | 194 | GL_INCR_WRAP, // StencilAction::IncrementWrap |
| 195 | GL_DECR_WRAP // StencilAction::DecrementWrap | 195 | GL_DECR_WRAP // StencilAction::DecrementWrap |
| 196 | }; | 196 | }; |
| 197 | 197 | ||
| 198 | // Range check table for input | 198 | // Range check table for input |
| @@ -207,18 +207,12 @@ inline GLenum StencilOp(Pica::Regs::StencilAction action) { | |||
| 207 | } | 207 | } |
| 208 | 208 | ||
| 209 | inline GLvec4 ColorRGBA8(const u32 color) { | 209 | inline GLvec4 ColorRGBA8(const u32 color) { |
| 210 | return { { (color >> 0 & 0xFF) / 255.0f, | 210 | return {{(color >> 0 & 0xFF) / 255.0f, (color >> 8 & 0xFF) / 255.0f, |
| 211 | (color >> 8 & 0xFF) / 255.0f, | 211 | (color >> 16 & 0xFF) / 255.0f, (color >> 24 & 0xFF) / 255.0f}}; |
| 212 | (color >> 16 & 0xFF) / 255.0f, | ||
| 213 | (color >> 24 & 0xFF) / 255.0f | ||
| 214 | } }; | ||
| 215 | } | 212 | } |
| 216 | 213 | ||
| 217 | inline std::array<GLfloat, 3> LightColor(const Pica::Regs::LightColor& color) { | 214 | inline std::array<GLfloat, 3> LightColor(const Pica::Regs::LightColor& color) { |
| 218 | return { { color.r / 255.0f, | 215 | return {{color.r / 255.0f, color.g / 255.0f, color.b / 255.0f}}; |
| 219 | color.g / 255.0f, | ||
| 220 | color.b / 255.0f | ||
| 221 | } }; | ||
| 222 | } | 216 | } |
| 223 | 217 | ||
| 224 | } // namespace | 218 | } // 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 { | |||
| 89 | static std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(const float width, const float height) { | 89 | static std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(const float width, const float height) { |
| 90 | std::array<GLfloat, 3 * 2> matrix; | 90 | std::array<GLfloat, 3 * 2> matrix; |
| 91 | 91 | ||
| 92 | matrix[0] = 2.f / width; matrix[2] = 0.f; matrix[4] = -1.f; | 92 | matrix[0] = 2.f / width; |
| 93 | matrix[1] = 0.f; matrix[3] = -2.f / height; matrix[5] = 1.f; | 93 | matrix[2] = 0.f; |
| 94 | matrix[4] = -1.f; | ||
| 95 | matrix[1] = 0.f; | ||
| 96 | matrix[3] = -2.f / height; | ||
| 97 | matrix[5] = 1.f; | ||
| 94 | // Last matrix row is implicitly assumed to be [0, 0, 1]. | 98 | // Last matrix row is implicitly assumed to be [0, 0, 1]. |
| 95 | 99 | ||
| 96 | return matrix; | 100 | return matrix; |
| @@ -98,7 +102,7 @@ static std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(const float width, cons | |||
| 98 | 102 | ||
| 99 | /// RendererOpenGL constructor | 103 | /// RendererOpenGL constructor |
| 100 | RendererOpenGL::RendererOpenGL() { | 104 | RendererOpenGL::RendererOpenGL() { |
| 101 | resolution_width = std::max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth); | 105 | resolution_width = std::max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth); |
| 102 | resolution_height = VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight; | 106 | resolution_height = VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight; |
| 103 | } | 107 | } |
| 104 | 108 | ||
| @@ -116,13 +120,15 @@ void RendererOpenGL::SwapBuffers() { | |||
| 116 | const auto& framebuffer = GPU::g_regs.framebuffer_config[i]; | 120 | const auto& framebuffer = GPU::g_regs.framebuffer_config[i]; |
| 117 | 121 | ||
| 118 | // Main LCD (0): 0x1ED02204, Sub LCD (1): 0x1ED02A04 | 122 | // Main LCD (0): 0x1ED02204, Sub LCD (1): 0x1ED02A04 |
| 119 | u32 lcd_color_addr = (i == 0) ? LCD_REG_INDEX(color_fill_top) : LCD_REG_INDEX(color_fill_bottom); | 123 | u32 lcd_color_addr = |
| 124 | (i == 0) ? LCD_REG_INDEX(color_fill_top) : LCD_REG_INDEX(color_fill_bottom); | ||
| 120 | lcd_color_addr = HW::VADDR_LCD + 4 * lcd_color_addr; | 125 | lcd_color_addr = HW::VADDR_LCD + 4 * lcd_color_addr; |
| 121 | LCD::Regs::ColorFill color_fill = {0}; | 126 | LCD::Regs::ColorFill color_fill = {0}; |
| 122 | LCD::Read(color_fill.raw, lcd_color_addr); | 127 | LCD::Read(color_fill.raw, lcd_color_addr); |
| 123 | 128 | ||
| 124 | if (color_fill.is_enabled) { | 129 | if (color_fill.is_enabled) { |
| 125 | LoadColorToActiveGLTexture(color_fill.color_r, color_fill.color_g, color_fill.color_b, screen_infos[i].texture); | 130 | LoadColorToActiveGLTexture(color_fill.color_r, color_fill.color_g, color_fill.color_b, |
| 131 | screen_infos[i].texture); | ||
| 126 | 132 | ||
| 127 | // Resize the texture in case the framebuffer size has changed | 133 | // Resize the texture in case the framebuffer size has changed |
| 128 | screen_infos[i].texture.width = 1; | 134 | screen_infos[i].texture.width = 1; |
| @@ -172,15 +178,14 @@ void RendererOpenGL::SwapBuffers() { | |||
| 172 | * Loads framebuffer from emulated memory into the active OpenGL texture. | 178 | * Loads framebuffer from emulated memory into the active OpenGL texture. |
| 173 | */ | 179 | */ |
| 174 | void RendererOpenGL::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& framebuffer, | 180 | void RendererOpenGL::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& framebuffer, |
| 175 | ScreenInfo& screen_info) { | 181 | ScreenInfo& screen_info) { |
| 176 | 182 | ||
| 177 | const PAddr framebuffer_addr = framebuffer.active_fb == 0 ? | 183 | const PAddr framebuffer_addr = |
| 178 | framebuffer.address_left1 : framebuffer.address_left2; | 184 | framebuffer.active_fb == 0 ? framebuffer.address_left1 : framebuffer.address_left2; |
| 179 | 185 | ||
| 180 | LOG_TRACE(Render_OpenGL, "0x%08x bytes from 0x%08x(%dx%d), fmt %x", | 186 | LOG_TRACE(Render_OpenGL, "0x%08x bytes from 0x%08x(%dx%d), fmt %x", |
| 181 | framebuffer.stride * framebuffer.height, | 187 | framebuffer.stride * framebuffer.height, framebuffer_addr, (int)framebuffer.width, |
| 182 | framebuffer_addr, (int)framebuffer.width, | 188 | (int)framebuffer.height, (int)framebuffer.format); |
| 183 | (int)framebuffer.height, (int)framebuffer.format); | ||
| 184 | 189 | ||
| 185 | int bpp = GPU::Regs::BytesPerPixel(framebuffer.color_format); | 190 | int bpp = GPU::Regs::BytesPerPixel(framebuffer.color_format); |
| 186 | size_t pixel_stride = framebuffer.stride / bpp; | 191 | size_t pixel_stride = framebuffer.stride / bpp; |
| @@ -192,7 +197,8 @@ void RendererOpenGL::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& fram | |||
| 192 | // only allows rows to have a memory alignement of 4. | 197 | // only allows rows to have a memory alignement of 4. |
| 193 | ASSERT(pixel_stride % 4 == 0); | 198 | ASSERT(pixel_stride % 4 == 0); |
| 194 | 199 | ||
| 195 | if (!Rasterizer()->AccelerateDisplay(framebuffer, framebuffer_addr, static_cast<u32>(pixel_stride), screen_info)) { | 200 | if (!Rasterizer()->AccelerateDisplay(framebuffer, framebuffer_addr, |
| 201 | static_cast<u32>(pixel_stride), screen_info)) { | ||
| 196 | // Reset the screen info's display texture to its own permanent texture | 202 | // Reset the screen info's display texture to its own permanent texture |
| 197 | screen_info.display_texture = screen_info.texture.resource.handle; | 203 | screen_info.display_texture = screen_info.texture.resource.handle; |
| 198 | screen_info.display_texcoords = MathUtil::Rectangle<float>(0.f, 0.f, 1.f, 1.f); | 204 | 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 | |||
| 208 | glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)pixel_stride); | 214 | glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)pixel_stride); |
| 209 | 215 | ||
| 210 | // Update existing texture | 216 | // Update existing texture |
| 211 | // TODO: Test what happens on hardware when you change the framebuffer dimensions so that they | 217 | // TODO: Test what happens on hardware when you change the framebuffer dimensions so that |
| 218 | // they | ||
| 212 | // differ from the LCD resolution. | 219 | // differ from the LCD resolution. |
| 213 | // TODO: Applications could theoretically crash Citra here by specifying too large | 220 | // TODO: Applications could theoretically crash Citra here by specifying too large |
| 214 | // framebuffer sizes. We should make sure that this cannot happen. | 221 | // framebuffer sizes. We should make sure that this cannot happen. |
| 215 | glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, framebuffer.width, framebuffer.height, | 222 | glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, framebuffer.width, framebuffer.height, |
| 216 | screen_info.texture.gl_format, screen_info.texture.gl_type, framebuffer_data); | 223 | screen_info.texture.gl_format, screen_info.texture.gl_type, |
| 224 | framebuffer_data); | ||
| 217 | 225 | ||
| 218 | glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); | 226 | glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); |
| 219 | 227 | ||
| @@ -224,7 +232,8 @@ void RendererOpenGL::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& fram | |||
| 224 | 232 | ||
| 225 | /** | 233 | /** |
| 226 | * Fills active OpenGL texture with the given RGB color. | 234 | * Fills active OpenGL texture with the given RGB color. |
| 227 | * Since the color is solid, the texture can be 1x1 but will stretch across whatever it's rendered on. | 235 | * Since the color is solid, the texture can be 1x1 but will stretch across whatever it's rendered |
| 236 | * on. | ||
| 228 | * This has the added benefit of being *really fast*. | 237 | * This has the added benefit of being *really fast*. |
| 229 | */ | 238 | */ |
| 230 | void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, | 239 | 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 | |||
| 233 | state.Apply(); | 242 | state.Apply(); |
| 234 | 243 | ||
| 235 | glActiveTexture(GL_TEXTURE0); | 244 | glActiveTexture(GL_TEXTURE0); |
| 236 | u8 framebuffer_data[3] = { color_r, color_g, color_b }; | 245 | u8 framebuffer_data[3] = {color_r, color_g, color_b}; |
| 237 | 246 | ||
| 238 | // Update existing texture | 247 | // Update existing texture |
| 239 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, framebuffer_data); | 248 | 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 | |||
| 246 | * Initializes the OpenGL state and creates persistent objects. | 255 | * Initializes the OpenGL state and creates persistent objects. |
| 247 | */ | 256 | */ |
| 248 | void RendererOpenGL::InitOpenGLObjects() { | 257 | void RendererOpenGL::InitOpenGLObjects() { |
| 249 | glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, 0.0f); | 258 | glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, |
| 259 | 0.0f); | ||
| 250 | 260 | ||
| 251 | // Link shaders and get variable locations | 261 | // Link shaders and get variable locations |
| 252 | shader.Create(vertex_shader, fragment_shader); | 262 | shader.Create(vertex_shader, fragment_shader); |
| @@ -270,8 +280,10 @@ void RendererOpenGL::InitOpenGLObjects() { | |||
| 270 | 280 | ||
| 271 | // Attach vertex data to VAO | 281 | // Attach vertex data to VAO |
| 272 | glBufferData(GL_ARRAY_BUFFER, sizeof(ScreenRectVertex) * 4, nullptr, GL_STREAM_DRAW); | 282 | glBufferData(GL_ARRAY_BUFFER, sizeof(ScreenRectVertex) * 4, nullptr, GL_STREAM_DRAW); |
| 273 | glVertexAttribPointer(attrib_position, 2, GL_FLOAT, GL_FALSE, sizeof(ScreenRectVertex), (GLvoid*)offsetof(ScreenRectVertex, position)); | 283 | glVertexAttribPointer(attrib_position, 2, GL_FLOAT, GL_FALSE, sizeof(ScreenRectVertex), |
| 274 | glVertexAttribPointer(attrib_tex_coord, 2, GL_FLOAT, GL_FALSE, sizeof(ScreenRectVertex), (GLvoid*)offsetof(ScreenRectVertex, tex_coord)); | 284 | (GLvoid*)offsetof(ScreenRectVertex, position)); |
| 285 | glVertexAttribPointer(attrib_tex_coord, 2, GL_FLOAT, GL_FALSE, sizeof(ScreenRectVertex), | ||
| 286 | (GLvoid*)offsetof(ScreenRectVertex, tex_coord)); | ||
| 275 | glEnableVertexAttribArray(attrib_position); | 287 | glEnableVertexAttribArray(attrib_position); |
| 276 | glEnableVertexAttribArray(attrib_tex_coord); | 288 | glEnableVertexAttribArray(attrib_tex_coord); |
| 277 | 289 | ||
| @@ -352,23 +364,25 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, | |||
| 352 | 364 | ||
| 353 | glActiveTexture(GL_TEXTURE0); | 365 | glActiveTexture(GL_TEXTURE0); |
| 354 | glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0, | 366 | glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0, |
| 355 | texture.gl_format, texture.gl_type, nullptr); | 367 | texture.gl_format, texture.gl_type, nullptr); |
| 356 | 368 | ||
| 357 | state.texture_units[0].texture_2d = 0; | 369 | state.texture_units[0].texture_2d = 0; |
| 358 | state.Apply(); | 370 | state.Apply(); |
| 359 | } | 371 | } |
| 360 | 372 | ||
| 361 | /** | 373 | /** |
| 362 | * Draws a single texture to the emulator window, rotating the texture to correct for the 3DS's LCD rotation. | 374 | * Draws a single texture to the emulator window, rotating the texture to correct for the 3DS's LCD |
| 375 | * rotation. | ||
| 363 | */ | 376 | */ |
| 364 | void RendererOpenGL::DrawSingleScreenRotated(const ScreenInfo& screen_info, float x, float y, float w, float h) { | 377 | void RendererOpenGL::DrawSingleScreenRotated(const ScreenInfo& screen_info, float x, float y, |
| 378 | float w, float h) { | ||
| 365 | auto& texcoords = screen_info.display_texcoords; | 379 | auto& texcoords = screen_info.display_texcoords; |
| 366 | 380 | ||
| 367 | std::array<ScreenRectVertex, 4> vertices = {{ | 381 | std::array<ScreenRectVertex, 4> vertices = {{ |
| 368 | ScreenRectVertex(x, y, texcoords.bottom, texcoords.left), | 382 | ScreenRectVertex(x, y, texcoords.bottom, texcoords.left), |
| 369 | ScreenRectVertex(x+w, y, texcoords.bottom, texcoords.right), | 383 | ScreenRectVertex(x + w, y, texcoords.bottom, texcoords.right), |
| 370 | ScreenRectVertex(x, y+h, texcoords.top, texcoords.left), | 384 | ScreenRectVertex(x, y + h, texcoords.top, texcoords.left), |
| 371 | ScreenRectVertex(x+w, y+h, texcoords.top, texcoords.right), | 385 | ScreenRectVertex(x + w, y + h, texcoords.top, texcoords.right), |
| 372 | }}; | 386 | }}; |
| 373 | 387 | ||
| 374 | state.texture_units[0].texture_2d = screen_info.display_texture; | 388 | state.texture_units[0].texture_2d = screen_info.display_texture; |
| @@ -391,18 +405,20 @@ void RendererOpenGL::DrawScreens() { | |||
| 391 | glClear(GL_COLOR_BUFFER_BIT); | 405 | glClear(GL_COLOR_BUFFER_BIT); |
| 392 | 406 | ||
| 393 | // Set projection matrix | 407 | // Set projection matrix |
| 394 | std::array<GLfloat, 3 * 2> ortho_matrix = MakeOrthographicMatrix((float)layout.width, | 408 | std::array<GLfloat, 3 * 2> ortho_matrix = |
| 395 | (float)layout.height); | 409 | MakeOrthographicMatrix((float)layout.width, (float)layout.height); |
| 396 | glUniformMatrix3x2fv(uniform_modelview_matrix, 1, GL_FALSE, ortho_matrix.data()); | 410 | glUniformMatrix3x2fv(uniform_modelview_matrix, 1, GL_FALSE, ortho_matrix.data()); |
| 397 | 411 | ||
| 398 | // Bind texture in Texture Unit 0 | 412 | // Bind texture in Texture Unit 0 |
| 399 | glActiveTexture(GL_TEXTURE0); | 413 | glActiveTexture(GL_TEXTURE0); |
| 400 | glUniform1i(uniform_color_texture, 0); | 414 | glUniform1i(uniform_color_texture, 0); |
| 401 | 415 | ||
| 402 | DrawSingleScreenRotated(screen_infos[0], (float)layout.top_screen.left, (float)layout.top_screen.top, | 416 | DrawSingleScreenRotated(screen_infos[0], (float)layout.top_screen.left, |
| 403 | (float)layout.top_screen.GetWidth(), (float)layout.top_screen.GetHeight()); | 417 | (float)layout.top_screen.top, (float)layout.top_screen.GetWidth(), |
| 404 | DrawSingleScreenRotated(screen_infos[1], (float)layout.bottom_screen.left,(float)layout.bottom_screen.top, | 418 | (float)layout.top_screen.GetHeight()); |
| 405 | (float)layout.bottom_screen.GetWidth(), (float)layout.bottom_screen.GetHeight()); | 419 | DrawSingleScreenRotated(screen_infos[1], (float)layout.bottom_screen.left, |
| 420 | (float)layout.bottom_screen.top, (float)layout.bottom_screen.GetWidth(), | ||
| 421 | (float)layout.bottom_screen.GetHeight()); | ||
| 406 | 422 | ||
| 407 | m_current_frame++; | 423 | m_current_frame++; |
| 408 | } | 424 | } |
| @@ -420,14 +436,16 @@ void RendererOpenGL::SetWindow(EmuWindow* window) { | |||
| 420 | } | 436 | } |
| 421 | 437 | ||
| 422 | static const char* GetSource(GLenum source) { | 438 | static const char* GetSource(GLenum source) { |
| 423 | #define RET(s) case GL_DEBUG_SOURCE_##s: return #s | 439 | #define RET(s) \ |
| 440 | case GL_DEBUG_SOURCE_##s: \ | ||
| 441 | return #s | ||
| 424 | switch (source) { | 442 | switch (source) { |
| 425 | RET(API); | 443 | RET(API); |
| 426 | RET(WINDOW_SYSTEM); | 444 | RET(WINDOW_SYSTEM); |
| 427 | RET(SHADER_COMPILER); | 445 | RET(SHADER_COMPILER); |
| 428 | RET(THIRD_PARTY); | 446 | RET(THIRD_PARTY); |
| 429 | RET(APPLICATION); | 447 | RET(APPLICATION); |
| 430 | RET(OTHER); | 448 | RET(OTHER); |
| 431 | default: | 449 | default: |
| 432 | UNREACHABLE(); | 450 | UNREACHABLE(); |
| 433 | } | 451 | } |
| @@ -435,23 +453,25 @@ static const char* GetSource(GLenum source) { | |||
| 435 | } | 453 | } |
| 436 | 454 | ||
| 437 | static const char* GetType(GLenum type) { | 455 | static const char* GetType(GLenum type) { |
| 438 | #define RET(t) case GL_DEBUG_TYPE_##t: return #t | 456 | #define RET(t) \ |
| 457 | case GL_DEBUG_TYPE_##t: \ | ||
| 458 | return #t | ||
| 439 | switch (type) { | 459 | switch (type) { |
| 440 | RET(ERROR); | 460 | RET(ERROR); |
| 441 | RET(DEPRECATED_BEHAVIOR); | 461 | RET(DEPRECATED_BEHAVIOR); |
| 442 | RET(UNDEFINED_BEHAVIOR); | 462 | RET(UNDEFINED_BEHAVIOR); |
| 443 | RET(PORTABILITY); | 463 | RET(PORTABILITY); |
| 444 | RET(PERFORMANCE); | 464 | RET(PERFORMANCE); |
| 445 | RET(OTHER); | 465 | RET(OTHER); |
| 446 | RET(MARKER); | 466 | RET(MARKER); |
| 447 | default: | 467 | default: |
| 448 | UNREACHABLE(); | 468 | UNREACHABLE(); |
| 449 | } | 469 | } |
| 450 | #undef RET | 470 | #undef RET |
| 451 | } | 471 | } |
| 452 | 472 | ||
| 453 | static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, | 473 | static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum severity, |
| 454 | const GLchar* message, const void* user_param) { | 474 | GLsizei length, const GLchar* message, const void* user_param) { |
| 455 | Log::Level level; | 475 | Log::Level level; |
| 456 | switch (severity) { | 476 | switch (severity) { |
| 457 | case GL_DEBUG_SEVERITY_HIGH: | 477 | case GL_DEBUG_SEVERITY_HIGH: |
| @@ -465,8 +485,8 @@ static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum | |||
| 465 | level = Log::Level::Debug; | 485 | level = Log::Level::Debug; |
| 466 | break; | 486 | break; |
| 467 | } | 487 | } |
| 468 | LOG_GENERIC(Log::Class::Render_OpenGL, level, "%s %s %d: %s", | 488 | LOG_GENERIC(Log::Class::Render_OpenGL, level, "%s %s %d: %s", GetSource(source), GetType(type), |
| 469 | GetSource(source), GetType(type), id, message); | 489 | id, message); |
| 470 | } | 490 | } |
| 471 | 491 | ||
| 472 | /// Initialize the renderer | 492 | /// 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 { | |||
| 38 | 38 | ||
| 39 | class RendererOpenGL : public RendererBase { | 39 | class RendererOpenGL : public RendererBase { |
| 40 | public: | 40 | public: |
| 41 | |||
| 42 | RendererOpenGL(); | 41 | RendererOpenGL(); |
| 43 | ~RendererOpenGL() override; | 42 | ~RendererOpenGL() override; |
| 44 | 43 | ||
| @@ -67,15 +66,14 @@ private: | |||
| 67 | 66 | ||
| 68 | // Loads framebuffer from emulated memory into the display information structure | 67 | // Loads framebuffer from emulated memory into the display information structure |
| 69 | void LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& framebuffer, | 68 | void LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& framebuffer, |
| 70 | ScreenInfo& screen_info); | 69 | ScreenInfo& screen_info); |
| 71 | // Fills active OpenGL texture with the given RGB color. | 70 | // Fills active OpenGL texture with the given RGB color. |
| 72 | void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, | 71 | void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, const TextureInfo& texture); |
| 73 | const TextureInfo& texture); | ||
| 74 | 72 | ||
| 75 | EmuWindow* render_window; ///< Handle to render window | 73 | EmuWindow* render_window; ///< Handle to render window |
| 76 | 74 | ||
| 77 | int resolution_width; ///< Current resolution width | 75 | int resolution_width; ///< Current resolution width |
| 78 | int resolution_height; ///< Current resolution height | 76 | int resolution_height; ///< Current resolution height |
| 79 | 77 | ||
| 80 | OpenGLState state; | 78 | OpenGLState state; |
| 81 | 79 | ||
| @@ -83,7 +81,8 @@ private: | |||
| 83 | OGLVertexArray vertex_array; | 81 | OGLVertexArray vertex_array; |
| 84 | OGLBuffer vertex_buffer; | 82 | OGLBuffer vertex_buffer; |
| 85 | OGLShader shader; | 83 | OGLShader shader; |
| 86 | std::array<ScreenInfo, 2> screen_infos; ///< Display information for top and bottom screens respectively | 84 | std::array<ScreenInfo, 2> |
| 85 | screen_infos; ///< Display information for top and bottom screens respectively | ||
| 87 | // Shader uniform location indices | 86 | // Shader uniform location indices |
| 88 | GLuint uniform_modelview_matrix; | 87 | GLuint uniform_modelview_matrix; |
| 89 | GLuint uniform_color_texture; | 88 | GLuint uniform_color_texture; |