diff options
25 files changed, 502 insertions, 125 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index f617665de..b474eb363 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -100,6 +100,8 @@ add_library(video_core STATIC | |||
| 100 | renderer_null/null_rasterizer.h | 100 | renderer_null/null_rasterizer.h |
| 101 | renderer_null/renderer_null.cpp | 101 | renderer_null/renderer_null.cpp |
| 102 | renderer_null/renderer_null.h | 102 | renderer_null/renderer_null.h |
| 103 | renderer_opengl/blit_image.cpp | ||
| 104 | renderer_opengl/blit_image.h | ||
| 103 | renderer_opengl/gl_buffer_cache.cpp | 105 | renderer_opengl/gl_buffer_cache.cpp |
| 104 | renderer_opengl/gl_buffer_cache.h | 106 | renderer_opengl/gl_buffer_cache.h |
| 105 | renderer_opengl/gl_compute_pipeline.cpp | 107 | renderer_opengl/gl_compute_pipeline.cpp |
diff --git a/src/video_core/engines/draw_manager.cpp b/src/video_core/engines/draw_manager.cpp index 2437121ce..1d22d25f1 100644 --- a/src/video_core/engines/draw_manager.cpp +++ b/src/video_core/engines/draw_manager.cpp | |||
| @@ -51,6 +51,10 @@ void DrawManager::ProcessMethodCall(u32 method, u32 argument) { | |||
| 51 | LOG_WARNING(HW_GPU, "(STUBBED) called"); | 51 | LOG_WARNING(HW_GPU, "(STUBBED) called"); |
| 52 | break; | 52 | break; |
| 53 | } | 53 | } |
| 54 | case MAXWELL3D_REG_INDEX(draw_texture.src_y0): { | ||
| 55 | DrawTexture(); | ||
| 56 | break; | ||
| 57 | } | ||
| 54 | default: | 58 | default: |
| 55 | break; | 59 | break; |
| 56 | } | 60 | } |
| @@ -179,6 +183,33 @@ void DrawManager::DrawIndexSmall(u32 argument) { | |||
| 179 | ProcessDraw(true, 1); | 183 | ProcessDraw(true, 1); |
| 180 | } | 184 | } |
| 181 | 185 | ||
| 186 | void DrawManager::DrawTexture() { | ||
| 187 | const auto& regs{maxwell3d->regs}; | ||
| 188 | draw_texture_state.dst_x0 = static_cast<float>(regs.draw_texture.dst_x0) / 4096.f; | ||
| 189 | draw_texture_state.dst_y0 = static_cast<float>(regs.draw_texture.dst_y0) / 4096.f; | ||
| 190 | const auto dst_width = static_cast<float>(regs.draw_texture.dst_width) / 4096.f; | ||
| 191 | const auto dst_height = static_cast<float>(regs.draw_texture.dst_height) / 4096.f; | ||
| 192 | const bool lower_left{regs.window_origin.mode != | ||
| 193 | Maxwell3D::Regs::WindowOrigin::Mode::UpperLeft}; | ||
| 194 | if (lower_left) { | ||
| 195 | draw_texture_state.dst_y0 -= dst_height; | ||
| 196 | } | ||
| 197 | draw_texture_state.dst_x1 = draw_texture_state.dst_x0 + dst_width; | ||
| 198 | draw_texture_state.dst_y1 = draw_texture_state.dst_y0 + dst_height; | ||
| 199 | draw_texture_state.src_x0 = static_cast<float>(regs.draw_texture.src_x0) / 4096.f; | ||
| 200 | draw_texture_state.src_y0 = static_cast<float>(regs.draw_texture.src_y0) / 4096.f; | ||
| 201 | draw_texture_state.src_x1 = | ||
| 202 | (static_cast<float>(regs.draw_texture.dx_du) / 4294967296.f) * dst_width + | ||
| 203 | draw_texture_state.src_x0; | ||
| 204 | draw_texture_state.src_y1 = | ||
| 205 | (static_cast<float>(regs.draw_texture.dy_dv) / 4294967296.f) * dst_height + | ||
| 206 | draw_texture_state.src_y0; | ||
| 207 | draw_texture_state.src_sampler = regs.draw_texture.src_sampler; | ||
| 208 | draw_texture_state.src_texture = regs.draw_texture.src_texture; | ||
| 209 | |||
| 210 | maxwell3d->rasterizer->DrawTexture(); | ||
| 211 | } | ||
| 212 | |||
| 182 | void DrawManager::UpdateTopology() { | 213 | void DrawManager::UpdateTopology() { |
| 183 | const auto& regs{maxwell3d->regs}; | 214 | const auto& regs{maxwell3d->regs}; |
| 184 | switch (regs.primitive_topology_control) { | 215 | switch (regs.primitive_topology_control) { |
diff --git a/src/video_core/engines/draw_manager.h b/src/video_core/engines/draw_manager.h index 58d1b2d59..7c22c49f1 100644 --- a/src/video_core/engines/draw_manager.h +++ b/src/video_core/engines/draw_manager.h | |||
| @@ -32,6 +32,19 @@ public: | |||
| 32 | std::vector<u8> inline_index_draw_indexes; | 32 | std::vector<u8> inline_index_draw_indexes; |
| 33 | }; | 33 | }; |
| 34 | 34 | ||
| 35 | struct DrawTextureState { | ||
| 36 | f32 dst_x0; | ||
| 37 | f32 dst_y0; | ||
| 38 | f32 dst_x1; | ||
| 39 | f32 dst_y1; | ||
| 40 | f32 src_x0; | ||
| 41 | f32 src_y0; | ||
| 42 | f32 src_x1; | ||
| 43 | f32 src_y1; | ||
| 44 | u32 src_sampler; | ||
| 45 | u32 src_texture; | ||
| 46 | }; | ||
| 47 | |||
| 35 | struct IndirectParams { | 48 | struct IndirectParams { |
| 36 | bool is_indexed; | 49 | bool is_indexed; |
| 37 | bool include_count; | 50 | bool include_count; |
| @@ -64,6 +77,10 @@ public: | |||
| 64 | return draw_state; | 77 | return draw_state; |
| 65 | } | 78 | } |
| 66 | 79 | ||
| 80 | const DrawTextureState& GetDrawTextureState() const { | ||
| 81 | return draw_texture_state; | ||
| 82 | } | ||
| 83 | |||
| 67 | IndirectParams& GetIndirectParams() { | 84 | IndirectParams& GetIndirectParams() { |
| 68 | return indirect_state; | 85 | return indirect_state; |
| 69 | } | 86 | } |
| @@ -81,6 +98,8 @@ private: | |||
| 81 | 98 | ||
| 82 | void DrawIndexSmall(u32 argument); | 99 | void DrawIndexSmall(u32 argument); |
| 83 | 100 | ||
| 101 | void DrawTexture(); | ||
| 102 | |||
| 84 | void UpdateTopology(); | 103 | void UpdateTopology(); |
| 85 | 104 | ||
| 86 | void ProcessDraw(bool draw_indexed, u32 instance_count); | 105 | void ProcessDraw(bool draw_indexed, u32 instance_count); |
| @@ -89,6 +108,7 @@ private: | |||
| 89 | 108 | ||
| 90 | Maxwell3D* maxwell3d{}; | 109 | Maxwell3D* maxwell3d{}; |
| 91 | State draw_state{}; | 110 | State draw_state{}; |
| 111 | DrawTextureState draw_texture_state{}; | ||
| 92 | IndirectParams indirect_state{}; | 112 | IndirectParams indirect_state{}; |
| 93 | }; | 113 | }; |
| 94 | } // namespace Tegra::Engines | 114 | } // namespace Tegra::Engines |
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 68ceda519..ae9da6290 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp | |||
| @@ -149,6 +149,7 @@ bool Maxwell3D::IsMethodExecutable(u32 method) { | |||
| 149 | case MAXWELL3D_REG_INDEX(inline_index_4x8.index0): | 149 | case MAXWELL3D_REG_INDEX(inline_index_4x8.index0): |
| 150 | case MAXWELL3D_REG_INDEX(vertex_array_instance_first): | 150 | case MAXWELL3D_REG_INDEX(vertex_array_instance_first): |
| 151 | case MAXWELL3D_REG_INDEX(vertex_array_instance_subsequent): | 151 | case MAXWELL3D_REG_INDEX(vertex_array_instance_subsequent): |
| 152 | case MAXWELL3D_REG_INDEX(draw_texture.src_y0): | ||
| 152 | case MAXWELL3D_REG_INDEX(wait_for_idle): | 153 | case MAXWELL3D_REG_INDEX(wait_for_idle): |
| 153 | case MAXWELL3D_REG_INDEX(shadow_ram_control): | 154 | case MAXWELL3D_REG_INDEX(shadow_ram_control): |
| 154 | case MAXWELL3D_REG_INDEX(load_mme.instruction_ptr): | 155 | case MAXWELL3D_REG_INDEX(load_mme.instruction_ptr): |
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 0b2fd2928..c89969bb4 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -1599,6 +1599,20 @@ public: | |||
| 1599 | }; | 1599 | }; |
| 1600 | static_assert(sizeof(TIRModulationCoeff) == 0x4); | 1600 | static_assert(sizeof(TIRModulationCoeff) == 0x4); |
| 1601 | 1601 | ||
| 1602 | struct DrawTexture { | ||
| 1603 | s32 dst_x0; | ||
| 1604 | s32 dst_y0; | ||
| 1605 | s32 dst_width; | ||
| 1606 | s32 dst_height; | ||
| 1607 | s64 dx_du; | ||
| 1608 | s64 dy_dv; | ||
| 1609 | u32 src_sampler; | ||
| 1610 | u32 src_texture; | ||
| 1611 | s32 src_x0; | ||
| 1612 | s32 src_y0; | ||
| 1613 | }; | ||
| 1614 | static_assert(sizeof(DrawTexture) == 0x30); | ||
| 1615 | |||
| 1602 | struct ReduceColorThreshold { | 1616 | struct ReduceColorThreshold { |
| 1603 | union { | 1617 | union { |
| 1604 | BitField<0, 8, u32> all_hit_once; | 1618 | BitField<0, 8, u32> all_hit_once; |
| @@ -2751,7 +2765,7 @@ public: | |||
| 2751 | u32 reserved_sw_method2; ///< 0x102C | 2765 | u32 reserved_sw_method2; ///< 0x102C |
| 2752 | std::array<TIRModulationCoeff, 5> tir_modulation_coeff; ///< 0x1030 | 2766 | std::array<TIRModulationCoeff, 5> tir_modulation_coeff; ///< 0x1030 |
| 2753 | std::array<u32, 15> spare_nop; ///< 0x1044 | 2767 | std::array<u32, 15> spare_nop; ///< 0x1044 |
| 2754 | INSERT_PADDING_BYTES_NOINIT(0x30); | 2768 | DrawTexture draw_texture; ///< 0x1080 |
| 2755 | std::array<u32, 7> reserved_sw_method3_to_7; ///< 0x10B0 | 2769 | std::array<u32, 7> reserved_sw_method3_to_7; ///< 0x10B0 |
| 2756 | ReduceColorThreshold reduce_color_thresholds_unorm8; ///< 0x10CC | 2770 | ReduceColorThreshold reduce_color_thresholds_unorm8; ///< 0x10CC |
| 2757 | std::array<u32, 4> reserved_sw_method10_to_13; ///< 0x10D0 | 2771 | std::array<u32, 4> reserved_sw_method10_to_13; ///< 0x10D0 |
diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt index f275b2aa9..e968ae220 100644 --- a/src/video_core/host_shaders/CMakeLists.txt +++ b/src/video_core/host_shaders/CMakeLists.txt | |||
| @@ -11,6 +11,7 @@ set(GLSL_INCLUDES | |||
| 11 | 11 | ||
| 12 | set(SHADER_FILES | 12 | set(SHADER_FILES |
| 13 | astc_decoder.comp | 13 | astc_decoder.comp |
| 14 | blit_color_float.frag | ||
| 14 | block_linear_unswizzle_2d.comp | 15 | block_linear_unswizzle_2d.comp |
| 15 | block_linear_unswizzle_3d.comp | 16 | block_linear_unswizzle_3d.comp |
| 16 | convert_abgr8_to_d24s8.frag | 17 | convert_abgr8_to_d24s8.frag |
| @@ -36,7 +37,6 @@ set(SHADER_FILES | |||
| 36 | smaa_blending_weight_calculation.frag | 37 | smaa_blending_weight_calculation.frag |
| 37 | smaa_neighborhood_blending.vert | 38 | smaa_neighborhood_blending.vert |
| 38 | smaa_neighborhood_blending.frag | 39 | smaa_neighborhood_blending.frag |
| 39 | vulkan_blit_color_float.frag | ||
| 40 | vulkan_blit_depth_stencil.frag | 40 | vulkan_blit_depth_stencil.frag |
| 41 | vulkan_fidelityfx_fsr_easu_fp16.comp | 41 | vulkan_fidelityfx_fsr_easu_fp16.comp |
| 42 | vulkan_fidelityfx_fsr_easu_fp32.comp | 42 | vulkan_fidelityfx_fsr_easu_fp32.comp |
diff --git a/src/video_core/host_shaders/vulkan_blit_color_float.frag b/src/video_core/host_shaders/blit_color_float.frag index c0c832296..c0c832296 100644 --- a/src/video_core/host_shaders/vulkan_blit_color_float.frag +++ b/src/video_core/host_shaders/blit_color_float.frag | |||
diff --git a/src/video_core/host_shaders/full_screen_triangle.vert b/src/video_core/host_shaders/full_screen_triangle.vert index 2c976b19f..d16d98995 100644 --- a/src/video_core/host_shaders/full_screen_triangle.vert +++ b/src/video_core/host_shaders/full_screen_triangle.vert | |||
| @@ -4,13 +4,20 @@ | |||
| 4 | #version 450 | 4 | #version 450 |
| 5 | 5 | ||
| 6 | #ifdef VULKAN | 6 | #ifdef VULKAN |
| 7 | #define VERTEX_ID gl_VertexIndex | ||
| 7 | #define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants { | 8 | #define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants { |
| 8 | #define END_PUSH_CONSTANTS }; | 9 | #define END_PUSH_CONSTANTS }; |
| 9 | #define UNIFORM(n) | 10 | #define UNIFORM(n) |
| 11 | #define FLIPY 1 | ||
| 10 | #else // ^^^ Vulkan ^^^ // vvv OpenGL vvv | 12 | #else // ^^^ Vulkan ^^^ // vvv OpenGL vvv |
| 13 | #define VERTEX_ID gl_VertexID | ||
| 11 | #define BEGIN_PUSH_CONSTANTS | 14 | #define BEGIN_PUSH_CONSTANTS |
| 12 | #define END_PUSH_CONSTANTS | 15 | #define END_PUSH_CONSTANTS |
| 16 | #define FLIPY -1 | ||
| 13 | #define UNIFORM(n) layout (location = n) uniform | 17 | #define UNIFORM(n) layout (location = n) uniform |
| 18 | out gl_PerVertex { | ||
| 19 | vec4 gl_Position; | ||
| 20 | }; | ||
| 14 | #endif | 21 | #endif |
| 15 | 22 | ||
| 16 | BEGIN_PUSH_CONSTANTS | 23 | BEGIN_PUSH_CONSTANTS |
| @@ -21,8 +28,8 @@ END_PUSH_CONSTANTS | |||
| 21 | layout(location = 0) out vec2 texcoord; | 28 | layout(location = 0) out vec2 texcoord; |
| 22 | 29 | ||
| 23 | void main() { | 30 | void main() { |
| 24 | float x = float((gl_VertexIndex & 1) << 2); | 31 | float x = float((VERTEX_ID & 1) << 2); |
| 25 | float y = float((gl_VertexIndex & 2) << 1); | 32 | float y = float((VERTEX_ID & 2) << 1); |
| 26 | gl_Position = vec4(x - 1.0, y - 1.0, 0.0, 1.0); | 33 | gl_Position = vec4(x - 1.0, FLIPY * (y - 1.0), 0.0, 1.0); |
| 27 | texcoord = fma(vec2(x, y) / 2.0, tex_scale, tex_offset); | 34 | texcoord = fma(vec2(x, y) / 2.0, tex_scale, tex_offset); |
| 28 | } | 35 | } |
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index 1735b6164..33e2610bc 100644 --- a/src/video_core/rasterizer_interface.h +++ b/src/video_core/rasterizer_interface.h | |||
| @@ -47,6 +47,9 @@ public: | |||
| 47 | /// Dispatches an indirect draw invocation | 47 | /// Dispatches an indirect draw invocation |
| 48 | virtual void DrawIndirect() {} | 48 | virtual void DrawIndirect() {} |
| 49 | 49 | ||
| 50 | /// Dispatches an draw texture invocation | ||
| 51 | virtual void DrawTexture() = 0; | ||
| 52 | |||
| 50 | /// Clear the current framebuffer | 53 | /// Clear the current framebuffer |
| 51 | virtual void Clear(u32 layer_count) = 0; | 54 | virtual void Clear(u32 layer_count) = 0; |
| 52 | 55 | ||
diff --git a/src/video_core/renderer_null/null_rasterizer.cpp b/src/video_core/renderer_null/null_rasterizer.cpp index 2c11345d7..2b5c7defa 100644 --- a/src/video_core/renderer_null/null_rasterizer.cpp +++ b/src/video_core/renderer_null/null_rasterizer.cpp | |||
| @@ -21,6 +21,7 @@ RasterizerNull::RasterizerNull(Core::Memory::Memory& cpu_memory_, Tegra::GPU& gp | |||
| 21 | RasterizerNull::~RasterizerNull() = default; | 21 | RasterizerNull::~RasterizerNull() = default; |
| 22 | 22 | ||
| 23 | void RasterizerNull::Draw(bool is_indexed, u32 instance_count) {} | 23 | void RasterizerNull::Draw(bool is_indexed, u32 instance_count) {} |
| 24 | void RasterizerNull::DrawTexture() {} | ||
| 24 | void RasterizerNull::Clear(u32 layer_count) {} | 25 | void RasterizerNull::Clear(u32 layer_count) {} |
| 25 | void RasterizerNull::DispatchCompute() {} | 26 | void RasterizerNull::DispatchCompute() {} |
| 26 | void RasterizerNull::ResetCounter(VideoCore::QueryType type) {} | 27 | void RasterizerNull::ResetCounter(VideoCore::QueryType type) {} |
diff --git a/src/video_core/renderer_null/null_rasterizer.h b/src/video_core/renderer_null/null_rasterizer.h index 2112aa70e..51f896e43 100644 --- a/src/video_core/renderer_null/null_rasterizer.h +++ b/src/video_core/renderer_null/null_rasterizer.h | |||
| @@ -31,6 +31,7 @@ public: | |||
| 31 | ~RasterizerNull() override; | 31 | ~RasterizerNull() override; |
| 32 | 32 | ||
| 33 | void Draw(bool is_indexed, u32 instance_count) override; | 33 | void Draw(bool is_indexed, u32 instance_count) override; |
| 34 | void DrawTexture() override; | ||
| 34 | void Clear(u32 layer_count) override; | 35 | void Clear(u32 layer_count) override; |
| 35 | void DispatchCompute() override; | 36 | void DispatchCompute() override; |
| 36 | void ResetCounter(VideoCore::QueryType type) override; | 37 | void ResetCounter(VideoCore::QueryType type) override; |
diff --git a/src/video_core/renderer_opengl/blit_image.cpp b/src/video_core/renderer_opengl/blit_image.cpp new file mode 100644 index 000000000..9a560a73b --- /dev/null +++ b/src/video_core/renderer_opengl/blit_image.cpp | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <algorithm> | ||
| 5 | |||
| 6 | #include "video_core/host_shaders/blit_color_float_frag.h" | ||
| 7 | #include "video_core/host_shaders/full_screen_triangle_vert.h" | ||
| 8 | #include "video_core/renderer_opengl/blit_image.h" | ||
| 9 | #include "video_core/renderer_opengl/gl_shader_manager.h" | ||
| 10 | #include "video_core/renderer_opengl/gl_shader_util.h" | ||
| 11 | |||
| 12 | namespace OpenGL { | ||
| 13 | |||
| 14 | BlitImageHelper::BlitImageHelper(ProgramManager& program_manager_) | ||
| 15 | : program_manager(program_manager_), | ||
| 16 | full_screen_vert(CreateProgram(HostShaders::FULL_SCREEN_TRIANGLE_VERT, GL_VERTEX_SHADER)), | ||
| 17 | blit_color_to_color_frag( | ||
| 18 | CreateProgram(HostShaders::BLIT_COLOR_FLOAT_FRAG, GL_FRAGMENT_SHADER)) {} | ||
| 19 | |||
| 20 | BlitImageHelper::~BlitImageHelper() = default; | ||
| 21 | |||
| 22 | void BlitImageHelper::BlitColor(GLuint dst_framebuffer, GLuint src_image_view, GLuint src_sampler, | ||
| 23 | const Region2D& dst_region, const Region2D& src_region, | ||
| 24 | const Extent3D& src_size) { | ||
| 25 | glEnable(GL_CULL_FACE); | ||
| 26 | glDisable(GL_COLOR_LOGIC_OP); | ||
| 27 | glDisable(GL_DEPTH_TEST); | ||
| 28 | glDisable(GL_STENCIL_TEST); | ||
| 29 | glDisable(GL_POLYGON_OFFSET_FILL); | ||
| 30 | glDisable(GL_RASTERIZER_DISCARD); | ||
| 31 | glDisable(GL_ALPHA_TEST); | ||
| 32 | glDisablei(GL_BLEND, 0); | ||
| 33 | glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); | ||
| 34 | glCullFace(GL_BACK); | ||
| 35 | glFrontFace(GL_CW); | ||
| 36 | glColorMaski(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); | ||
| 37 | glDepthRangeIndexed(0, 0.0, 0.0); | ||
| 38 | |||
| 39 | program_manager.BindPresentPrograms(full_screen_vert.handle, blit_color_to_color_frag.handle); | ||
| 40 | glProgramUniform2f(full_screen_vert.handle, 0, | ||
| 41 | static_cast<float>(src_region.end.x - src_region.start.x) / | ||
| 42 | static_cast<float>(src_size.width), | ||
| 43 | static_cast<float>(src_region.end.y - src_region.start.y) / | ||
| 44 | static_cast<float>(src_size.height)); | ||
| 45 | glProgramUniform2f(full_screen_vert.handle, 1, | ||
| 46 | static_cast<float>(src_region.start.x) / static_cast<float>(src_size.width), | ||
| 47 | static_cast<float>(src_region.start.y) / | ||
| 48 | static_cast<float>(src_size.height)); | ||
| 49 | glViewport(std::min(dst_region.start.x, dst_region.end.x), | ||
| 50 | std::min(dst_region.start.y, dst_region.end.y), | ||
| 51 | std::abs(dst_region.end.x - dst_region.start.x), | ||
| 52 | std::abs(dst_region.end.y - dst_region.start.y)); | ||
| 53 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst_framebuffer); | ||
| 54 | glBindSampler(0, src_sampler); | ||
| 55 | glBindTextureUnit(0, src_image_view); | ||
| 56 | glClear(GL_COLOR_BUFFER_BIT); | ||
| 57 | glDrawArrays(GL_TRIANGLES, 0, 3); | ||
| 58 | } | ||
| 59 | } // namespace OpenGL | ||
diff --git a/src/video_core/renderer_opengl/blit_image.h b/src/video_core/renderer_opengl/blit_image.h new file mode 100644 index 000000000..5a2b12d16 --- /dev/null +++ b/src/video_core/renderer_opengl/blit_image.h | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <glad/glad.h> | ||
| 7 | |||
| 8 | #include "video_core/engines/fermi_2d.h" | ||
| 9 | #include "video_core/renderer_opengl/gl_resource_manager.h" | ||
| 10 | #include "video_core/texture_cache/types.h" | ||
| 11 | |||
| 12 | namespace OpenGL { | ||
| 13 | |||
| 14 | using VideoCommon::Extent3D; | ||
| 15 | using VideoCommon::Offset2D; | ||
| 16 | using VideoCommon::Region2D; | ||
| 17 | |||
| 18 | class ProgramManager; | ||
| 19 | class Framebuffer; | ||
| 20 | class ImageView; | ||
| 21 | |||
| 22 | class BlitImageHelper { | ||
| 23 | public: | ||
| 24 | explicit BlitImageHelper(ProgramManager& program_manager); | ||
| 25 | ~BlitImageHelper(); | ||
| 26 | |||
| 27 | void BlitColor(GLuint dst_framebuffer, GLuint src_image_view, GLuint src_sampler, | ||
| 28 | const Region2D& dst_region, const Region2D& src_region, | ||
| 29 | const Extent3D& src_size); | ||
| 30 | |||
| 31 | private: | ||
| 32 | ProgramManager& program_manager; | ||
| 33 | |||
| 34 | OGLProgram full_screen_vert; | ||
| 35 | OGLProgram blit_color_to_color_frag; | ||
| 36 | }; | ||
| 37 | |||
| 38 | } // namespace OpenGL | ||
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp index cee5c3247..22ed16ebf 100644 --- a/src/video_core/renderer_opengl/gl_device.cpp +++ b/src/video_core/renderer_opengl/gl_device.cpp | |||
| @@ -166,6 +166,7 @@ Device::Device(Core::Frontend::EmuWindow& emu_window) { | |||
| 166 | has_shader_int64 = HasExtension(extensions, "GL_ARB_gpu_shader_int64"); | 166 | has_shader_int64 = HasExtension(extensions, "GL_ARB_gpu_shader_int64"); |
| 167 | has_amd_shader_half_float = GLAD_GL_AMD_gpu_shader_half_float; | 167 | has_amd_shader_half_float = GLAD_GL_AMD_gpu_shader_half_float; |
| 168 | has_sparse_texture_2 = GLAD_GL_ARB_sparse_texture2; | 168 | has_sparse_texture_2 = GLAD_GL_ARB_sparse_texture2; |
| 169 | has_draw_texture = GLAD_GL_NV_draw_texture; | ||
| 169 | warp_size_potentially_larger_than_guest = !is_nvidia && !is_intel; | 170 | warp_size_potentially_larger_than_guest = !is_nvidia && !is_intel; |
| 170 | need_fastmath_off = is_nvidia; | 171 | need_fastmath_off = is_nvidia; |
| 171 | can_report_memory = GLAD_GL_NVX_gpu_memory_info; | 172 | can_report_memory = GLAD_GL_NVX_gpu_memory_info; |
diff --git a/src/video_core/renderer_opengl/gl_device.h b/src/video_core/renderer_opengl/gl_device.h index 2a72d84be..3ff8cad83 100644 --- a/src/video_core/renderer_opengl/gl_device.h +++ b/src/video_core/renderer_opengl/gl_device.h | |||
| @@ -4,6 +4,8 @@ | |||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <cstddef> | 6 | #include <cstddef> |
| 7 | #include <string> | ||
| 8 | |||
| 7 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 8 | #include "core/frontend/emu_window.h" | 10 | #include "core/frontend/emu_window.h" |
| 9 | #include "shader_recompiler/stage.h" | 11 | #include "shader_recompiler/stage.h" |
| @@ -146,6 +148,10 @@ public: | |||
| 146 | return has_sparse_texture_2; | 148 | return has_sparse_texture_2; |
| 147 | } | 149 | } |
| 148 | 150 | ||
| 151 | bool HasDrawTexture() const { | ||
| 152 | return has_draw_texture; | ||
| 153 | } | ||
| 154 | |||
| 149 | bool IsWarpSizePotentiallyLargerThanGuest() const { | 155 | bool IsWarpSizePotentiallyLargerThanGuest() const { |
| 150 | return warp_size_potentially_larger_than_guest; | 156 | return warp_size_potentially_larger_than_guest; |
| 151 | } | 157 | } |
| @@ -216,6 +222,7 @@ private: | |||
| 216 | bool has_shader_int64{}; | 222 | bool has_shader_int64{}; |
| 217 | bool has_amd_shader_half_float{}; | 223 | bool has_amd_shader_half_float{}; |
| 218 | bool has_sparse_texture_2{}; | 224 | bool has_sparse_texture_2{}; |
| 225 | bool has_draw_texture{}; | ||
| 219 | bool warp_size_potentially_larger_than_guest{}; | 226 | bool warp_size_potentially_larger_than_guest{}; |
| 220 | bool need_fastmath_off{}; | 227 | bool need_fastmath_off{}; |
| 221 | bool has_cbuf_ftou_bug{}; | 228 | bool has_cbuf_ftou_bug{}; |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 181857d9c..7bced675c 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -64,7 +64,8 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra | |||
| 64 | shader_cache(*this, emu_window_, device, texture_cache, buffer_cache, program_manager, | 64 | shader_cache(*this, emu_window_, device, texture_cache, buffer_cache, program_manager, |
| 65 | state_tracker, gpu.ShaderNotify()), | 65 | state_tracker, gpu.ShaderNotify()), |
| 66 | query_cache(*this), accelerate_dma(buffer_cache), | 66 | query_cache(*this), accelerate_dma(buffer_cache), |
| 67 | fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache) {} | 67 | fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache), |
| 68 | blit_image(program_manager_) {} | ||
| 68 | 69 | ||
| 69 | RasterizerOpenGL::~RasterizerOpenGL() = default; | 70 | RasterizerOpenGL::~RasterizerOpenGL() = default; |
| 70 | 71 | ||
| @@ -320,6 +321,47 @@ void RasterizerOpenGL::DrawIndirect() { | |||
| 320 | buffer_cache.SetDrawIndirect(nullptr); | 321 | buffer_cache.SetDrawIndirect(nullptr); |
| 321 | } | 322 | } |
| 322 | 323 | ||
| 324 | void RasterizerOpenGL::DrawTexture() { | ||
| 325 | MICROPROFILE_SCOPE(OpenGL_Drawing); | ||
| 326 | |||
| 327 | SCOPE_EXIT({ gpu.TickWork(); }); | ||
| 328 | query_cache.UpdateCounters(); | ||
| 329 | |||
| 330 | texture_cache.SynchronizeGraphicsDescriptors(); | ||
| 331 | texture_cache.UpdateRenderTargets(false); | ||
| 332 | |||
| 333 | SyncState(); | ||
| 334 | |||
| 335 | const auto& draw_texture_state = maxwell3d->draw_manager->GetDrawTextureState(); | ||
| 336 | const auto& sampler = texture_cache.GetGraphicsSampler(draw_texture_state.src_sampler); | ||
| 337 | const auto& texture = texture_cache.GetImageView(draw_texture_state.src_texture); | ||
| 338 | |||
| 339 | if (device.HasDrawTexture()) { | ||
| 340 | state_tracker.BindFramebuffer(texture_cache.GetFramebuffer()->Handle()); | ||
| 341 | |||
| 342 | glDrawTextureNV(texture.DefaultHandle(), sampler->Handle(), draw_texture_state.dst_x0, | ||
| 343 | draw_texture_state.dst_y0, draw_texture_state.dst_x1, | ||
| 344 | draw_texture_state.dst_y1, 0, | ||
| 345 | draw_texture_state.src_x0 / static_cast<float>(texture.size.width), | ||
| 346 | draw_texture_state.src_y0 / static_cast<float>(texture.size.height), | ||
| 347 | draw_texture_state.src_x1 / static_cast<float>(texture.size.width), | ||
| 348 | draw_texture_state.src_y1 / static_cast<float>(texture.size.height)); | ||
| 349 | } else { | ||
| 350 | Region2D dst_region = {Offset2D{.x = static_cast<s32>(draw_texture_state.dst_x0), | ||
| 351 | .y = static_cast<s32>(draw_texture_state.dst_y0)}, | ||
| 352 | Offset2D{.x = static_cast<s32>(draw_texture_state.dst_x1), | ||
| 353 | .y = static_cast<s32>(draw_texture_state.dst_y1)}}; | ||
| 354 | Region2D src_region = {Offset2D{.x = static_cast<s32>(draw_texture_state.src_x0), | ||
| 355 | .y = static_cast<s32>(draw_texture_state.src_y0)}, | ||
| 356 | Offset2D{.x = static_cast<s32>(draw_texture_state.src_x1), | ||
| 357 | .y = static_cast<s32>(draw_texture_state.src_y1)}}; | ||
| 358 | blit_image.BlitColor(texture_cache.GetFramebuffer()->Handle(), texture.DefaultHandle(), | ||
| 359 | sampler->Handle(), dst_region, src_region, texture.size); | ||
| 360 | } | ||
| 361 | |||
| 362 | ++num_queued_commands; | ||
| 363 | } | ||
| 364 | |||
| 323 | void RasterizerOpenGL::DispatchCompute() { | 365 | void RasterizerOpenGL::DispatchCompute() { |
| 324 | gpu_memory->FlushCaching(); | 366 | gpu_memory->FlushCaching(); |
| 325 | ComputePipeline* const pipeline{shader_cache.CurrentComputePipeline()}; | 367 | ComputePipeline* const pipeline{shader_cache.CurrentComputePipeline()}; |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index be4f76c18..0c45832ae 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include "video_core/engines/maxwell_dma.h" | 16 | #include "video_core/engines/maxwell_dma.h" |
| 17 | #include "video_core/rasterizer_accelerated.h" | 17 | #include "video_core/rasterizer_accelerated.h" |
| 18 | #include "video_core/rasterizer_interface.h" | 18 | #include "video_core/rasterizer_interface.h" |
| 19 | #include "video_core/renderer_opengl/blit_image.h" | ||
| 19 | #include "video_core/renderer_opengl/gl_buffer_cache.h" | 20 | #include "video_core/renderer_opengl/gl_buffer_cache.h" |
| 20 | #include "video_core/renderer_opengl/gl_device.h" | 21 | #include "video_core/renderer_opengl/gl_device.h" |
| 21 | #include "video_core/renderer_opengl/gl_fence_manager.h" | 22 | #include "video_core/renderer_opengl/gl_fence_manager.h" |
| @@ -70,6 +71,7 @@ public: | |||
| 70 | 71 | ||
| 71 | void Draw(bool is_indexed, u32 instance_count) override; | 72 | void Draw(bool is_indexed, u32 instance_count) override; |
| 72 | void DrawIndirect() override; | 73 | void DrawIndirect() override; |
| 74 | void DrawTexture() override; | ||
| 73 | void Clear(u32 layer_count) override; | 75 | void Clear(u32 layer_count) override; |
| 74 | void DispatchCompute() override; | 76 | void DispatchCompute() override; |
| 75 | void ResetCounter(VideoCore::QueryType type) override; | 77 | void ResetCounter(VideoCore::QueryType type) override; |
| @@ -224,6 +226,8 @@ private: | |||
| 224 | AccelerateDMA accelerate_dma; | 226 | AccelerateDMA accelerate_dma; |
| 225 | FenceManagerOpenGL fence_manager; | 227 | FenceManagerOpenGL fence_manager; |
| 226 | 228 | ||
| 229 | BlitImageHelper blit_image; | ||
| 230 | |||
| 227 | boost::container::static_vector<u32, MAX_IMAGE_VIEWS> image_view_indices; | 231 | boost::container::static_vector<u32, MAX_IMAGE_VIEWS> image_view_indices; |
| 228 | std::array<ImageViewId, MAX_IMAGE_VIEWS> image_view_ids; | 232 | std::array<ImageViewId, MAX_IMAGE_VIEWS> image_view_ids; |
| 229 | boost::container::static_vector<GLuint, MAX_TEXTURES> sampler_handles; | 233 | boost::container::static_vector<GLuint, MAX_TEXTURES> sampler_handles; |
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp index d9c29d8b7..98841ae65 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.cpp +++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp | |||
| @@ -1,2 +1,123 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | |||
| 4 | #include <glad/glad.h> | ||
| 5 | |||
| 6 | #include "video_core/renderer_opengl/gl_shader_manager.h" | ||
| 7 | |||
| 8 | namespace OpenGL { | ||
| 9 | |||
| 10 | static constexpr std::array ASSEMBLY_PROGRAM_ENUMS{ | ||
| 11 | GL_VERTEX_PROGRAM_NV, GL_TESS_CONTROL_PROGRAM_NV, GL_TESS_EVALUATION_PROGRAM_NV, | ||
| 12 | GL_GEOMETRY_PROGRAM_NV, GL_FRAGMENT_PROGRAM_NV, | ||
| 13 | }; | ||
| 14 | |||
| 15 | ProgramManager::ProgramManager(const Device& device) { | ||
| 16 | glCreateProgramPipelines(1, &pipeline.handle); | ||
| 17 | if (device.UseAssemblyShaders()) { | ||
| 18 | glEnable(GL_COMPUTE_PROGRAM_NV); | ||
| 19 | } | ||
| 20 | } | ||
| 21 | |||
| 22 | void ProgramManager::BindComputeProgram(GLuint program) { | ||
| 23 | glUseProgram(program); | ||
| 24 | is_compute_bound = true; | ||
| 25 | } | ||
| 26 | |||
| 27 | void ProgramManager::BindComputeAssemblyProgram(GLuint program) { | ||
| 28 | if (current_assembly_compute_program != program) { | ||
| 29 | current_assembly_compute_program = program; | ||
| 30 | glBindProgramARB(GL_COMPUTE_PROGRAM_NV, program); | ||
| 31 | } | ||
| 32 | UnbindPipeline(); | ||
| 33 | } | ||
| 34 | |||
| 35 | void ProgramManager::BindSourcePrograms(std::span<const OGLProgram, NUM_STAGES> programs) { | ||
| 36 | static constexpr std::array<GLenum, 5> stage_enums{ | ||
| 37 | GL_VERTEX_SHADER_BIT, GL_TESS_CONTROL_SHADER_BIT, GL_TESS_EVALUATION_SHADER_BIT, | ||
| 38 | GL_GEOMETRY_SHADER_BIT, GL_FRAGMENT_SHADER_BIT, | ||
| 39 | }; | ||
| 40 | for (size_t stage = 0; stage < NUM_STAGES; ++stage) { | ||
| 41 | if (current_programs[stage] != programs[stage].handle) { | ||
| 42 | current_programs[stage] = programs[stage].handle; | ||
| 43 | glUseProgramStages(pipeline.handle, stage_enums[stage], programs[stage].handle); | ||
| 44 | } | ||
| 45 | } | ||
| 46 | BindPipeline(); | ||
| 47 | } | ||
| 48 | |||
| 49 | void ProgramManager::BindPresentPrograms(GLuint vertex, GLuint fragment) { | ||
| 50 | if (current_programs[0] != vertex) { | ||
| 51 | current_programs[0] = vertex; | ||
| 52 | glUseProgramStages(pipeline.handle, GL_VERTEX_SHADER_BIT, vertex); | ||
| 53 | } | ||
| 54 | if (current_programs[4] != fragment) { | ||
| 55 | current_programs[4] = fragment; | ||
| 56 | glUseProgramStages(pipeline.handle, GL_FRAGMENT_SHADER_BIT, fragment); | ||
| 57 | } | ||
| 58 | glUseProgramStages( | ||
| 59 | pipeline.handle, | ||
| 60 | GL_TESS_CONTROL_SHADER_BIT | GL_TESS_EVALUATION_SHADER_BIT | GL_GEOMETRY_SHADER_BIT, 0); | ||
| 61 | current_programs[1] = 0; | ||
| 62 | current_programs[2] = 0; | ||
| 63 | current_programs[3] = 0; | ||
| 64 | |||
| 65 | if (current_stage_mask != 0) { | ||
| 66 | current_stage_mask = 0; | ||
| 67 | for (const GLenum program_type : ASSEMBLY_PROGRAM_ENUMS) { | ||
| 68 | glDisable(program_type); | ||
| 69 | } | ||
| 70 | } | ||
| 71 | BindPipeline(); | ||
| 72 | } | ||
| 73 | |||
| 74 | void ProgramManager::BindAssemblyPrograms(std::span<const OGLAssemblyProgram, NUM_STAGES> programs, | ||
| 75 | u32 stage_mask) { | ||
| 76 | const u32 changed_mask = current_stage_mask ^ stage_mask; | ||
| 77 | current_stage_mask = stage_mask; | ||
| 78 | |||
| 79 | if (changed_mask != 0) { | ||
| 80 | for (size_t stage = 0; stage < NUM_STAGES; ++stage) { | ||
| 81 | if (((changed_mask >> stage) & 1) != 0) { | ||
| 82 | if (((stage_mask >> stage) & 1) != 0) { | ||
| 83 | glEnable(ASSEMBLY_PROGRAM_ENUMS[stage]); | ||
| 84 | } else { | ||
| 85 | glDisable(ASSEMBLY_PROGRAM_ENUMS[stage]); | ||
| 86 | } | ||
| 87 | } | ||
| 88 | } | ||
| 89 | } | ||
| 90 | for (size_t stage = 0; stage < NUM_STAGES; ++stage) { | ||
| 91 | if (current_programs[stage] != programs[stage].handle) { | ||
| 92 | current_programs[stage] = programs[stage].handle; | ||
| 93 | glBindProgramARB(ASSEMBLY_PROGRAM_ENUMS[stage], programs[stage].handle); | ||
| 94 | } | ||
| 95 | } | ||
| 96 | UnbindPipeline(); | ||
| 97 | } | ||
| 98 | |||
| 99 | void ProgramManager::RestoreGuestCompute() {} | ||
| 100 | |||
| 101 | void ProgramManager::BindPipeline() { | ||
| 102 | if (!is_pipeline_bound) { | ||
| 103 | is_pipeline_bound = true; | ||
| 104 | glBindProgramPipeline(pipeline.handle); | ||
| 105 | } | ||
| 106 | UnbindCompute(); | ||
| 107 | } | ||
| 108 | |||
| 109 | void ProgramManager::UnbindPipeline() { | ||
| 110 | if (is_pipeline_bound) { | ||
| 111 | is_pipeline_bound = false; | ||
| 112 | glBindProgramPipeline(0); | ||
| 113 | } | ||
| 114 | UnbindCompute(); | ||
| 115 | } | ||
| 116 | |||
| 117 | void ProgramManager::UnbindCompute() { | ||
| 118 | if (is_compute_bound) { | ||
| 119 | is_compute_bound = false; | ||
| 120 | glUseProgram(0); | ||
| 121 | } | ||
| 122 | } | ||
| 123 | } // namespace OpenGL | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h index a84f5aeb3..07ffab77f 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.h +++ b/src/video_core/renderer_opengl/gl_shader_manager.h | |||
| @@ -6,8 +6,6 @@ | |||
| 6 | #include <array> | 6 | #include <array> |
| 7 | #include <span> | 7 | #include <span> |
| 8 | 8 | ||
| 9 | #include <glad/glad.h> | ||
| 10 | |||
| 11 | #include "video_core/renderer_opengl/gl_device.h" | 9 | #include "video_core/renderer_opengl/gl_device.h" |
| 12 | #include "video_core/renderer_opengl/gl_resource_manager.h" | 10 | #include "video_core/renderer_opengl/gl_resource_manager.h" |
| 13 | 11 | ||
| @@ -16,121 +14,28 @@ namespace OpenGL { | |||
| 16 | class ProgramManager { | 14 | class ProgramManager { |
| 17 | static constexpr size_t NUM_STAGES = 5; | 15 | static constexpr size_t NUM_STAGES = 5; |
| 18 | 16 | ||
| 19 | static constexpr std::array ASSEMBLY_PROGRAM_ENUMS{ | ||
| 20 | GL_VERTEX_PROGRAM_NV, GL_TESS_CONTROL_PROGRAM_NV, GL_TESS_EVALUATION_PROGRAM_NV, | ||
| 21 | GL_GEOMETRY_PROGRAM_NV, GL_FRAGMENT_PROGRAM_NV, | ||
| 22 | }; | ||
| 23 | |||
| 24 | public: | 17 | public: |
| 25 | explicit ProgramManager(const Device& device) { | 18 | explicit ProgramManager(const Device& device); |
| 26 | glCreateProgramPipelines(1, &pipeline.handle); | 19 | |
| 27 | if (device.UseAssemblyShaders()) { | 20 | void BindComputeProgram(GLuint program); |
| 28 | glEnable(GL_COMPUTE_PROGRAM_NV); | 21 | |
| 29 | } | 22 | void BindComputeAssemblyProgram(GLuint program); |
| 30 | } | 23 | |
| 31 | 24 | void BindSourcePrograms(std::span<const OGLProgram, NUM_STAGES> programs); | |
| 32 | void BindComputeProgram(GLuint program) { | 25 | |
| 33 | glUseProgram(program); | 26 | void BindPresentPrograms(GLuint vertex, GLuint fragment); |
| 34 | is_compute_bound = true; | ||
| 35 | } | ||
| 36 | |||
| 37 | void BindComputeAssemblyProgram(GLuint program) { | ||
| 38 | if (current_assembly_compute_program != program) { | ||
| 39 | current_assembly_compute_program = program; | ||
| 40 | glBindProgramARB(GL_COMPUTE_PROGRAM_NV, program); | ||
| 41 | } | ||
| 42 | UnbindPipeline(); | ||
| 43 | } | ||
| 44 | |||
| 45 | void BindSourcePrograms(std::span<const OGLProgram, NUM_STAGES> programs) { | ||
| 46 | static constexpr std::array<GLenum, 5> stage_enums{ | ||
| 47 | GL_VERTEX_SHADER_BIT, GL_TESS_CONTROL_SHADER_BIT, GL_TESS_EVALUATION_SHADER_BIT, | ||
| 48 | GL_GEOMETRY_SHADER_BIT, GL_FRAGMENT_SHADER_BIT, | ||
| 49 | }; | ||
| 50 | for (size_t stage = 0; stage < NUM_STAGES; ++stage) { | ||
| 51 | if (current_programs[stage] != programs[stage].handle) { | ||
| 52 | current_programs[stage] = programs[stage].handle; | ||
| 53 | glUseProgramStages(pipeline.handle, stage_enums[stage], programs[stage].handle); | ||
| 54 | } | ||
| 55 | } | ||
| 56 | BindPipeline(); | ||
| 57 | } | ||
| 58 | |||
| 59 | void BindPresentPrograms(GLuint vertex, GLuint fragment) { | ||
| 60 | if (current_programs[0] != vertex) { | ||
| 61 | current_programs[0] = vertex; | ||
| 62 | glUseProgramStages(pipeline.handle, GL_VERTEX_SHADER_BIT, vertex); | ||
| 63 | } | ||
| 64 | if (current_programs[4] != fragment) { | ||
| 65 | current_programs[4] = fragment; | ||
| 66 | glUseProgramStages(pipeline.handle, GL_FRAGMENT_SHADER_BIT, fragment); | ||
| 67 | } | ||
| 68 | glUseProgramStages( | ||
| 69 | pipeline.handle, | ||
| 70 | GL_TESS_CONTROL_SHADER_BIT | GL_TESS_EVALUATION_SHADER_BIT | GL_GEOMETRY_SHADER_BIT, 0); | ||
| 71 | current_programs[1] = 0; | ||
| 72 | current_programs[2] = 0; | ||
| 73 | current_programs[3] = 0; | ||
| 74 | |||
| 75 | if (current_stage_mask != 0) { | ||
| 76 | current_stage_mask = 0; | ||
| 77 | for (const GLenum program_type : ASSEMBLY_PROGRAM_ENUMS) { | ||
| 78 | glDisable(program_type); | ||
| 79 | } | ||
| 80 | } | ||
| 81 | BindPipeline(); | ||
| 82 | } | ||
| 83 | 27 | ||
| 84 | void BindAssemblyPrograms(std::span<const OGLAssemblyProgram, NUM_STAGES> programs, | 28 | void BindAssemblyPrograms(std::span<const OGLAssemblyProgram, NUM_STAGES> programs, |
| 85 | u32 stage_mask) { | 29 | u32 stage_mask); |
| 86 | const u32 changed_mask = current_stage_mask ^ stage_mask; | 30 | |
| 87 | current_stage_mask = stage_mask; | 31 | void RestoreGuestCompute(); |
| 88 | |||
| 89 | if (changed_mask != 0) { | ||
| 90 | for (size_t stage = 0; stage < NUM_STAGES; ++stage) { | ||
| 91 | if (((changed_mask >> stage) & 1) != 0) { | ||
| 92 | if (((stage_mask >> stage) & 1) != 0) { | ||
| 93 | glEnable(ASSEMBLY_PROGRAM_ENUMS[stage]); | ||
| 94 | } else { | ||
| 95 | glDisable(ASSEMBLY_PROGRAM_ENUMS[stage]); | ||
| 96 | } | ||
| 97 | } | ||
| 98 | } | ||
| 99 | } | ||
| 100 | for (size_t stage = 0; stage < NUM_STAGES; ++stage) { | ||
| 101 | if (current_programs[stage] != programs[stage].handle) { | ||
| 102 | current_programs[stage] = programs[stage].handle; | ||
| 103 | glBindProgramARB(ASSEMBLY_PROGRAM_ENUMS[stage], programs[stage].handle); | ||
| 104 | } | ||
| 105 | } | ||
| 106 | UnbindPipeline(); | ||
| 107 | } | ||
| 108 | |||
| 109 | void RestoreGuestCompute() {} | ||
| 110 | 32 | ||
| 111 | private: | 33 | private: |
| 112 | void BindPipeline() { | 34 | void BindPipeline(); |
| 113 | if (!is_pipeline_bound) { | 35 | |
| 114 | is_pipeline_bound = true; | 36 | void UnbindPipeline(); |
| 115 | glBindProgramPipeline(pipeline.handle); | 37 | |
| 116 | } | 38 | void UnbindCompute(); |
| 117 | UnbindCompute(); | ||
| 118 | } | ||
| 119 | |||
| 120 | void UnbindPipeline() { | ||
| 121 | if (is_pipeline_bound) { | ||
| 122 | is_pipeline_bound = false; | ||
| 123 | glBindProgramPipeline(0); | ||
| 124 | } | ||
| 125 | UnbindCompute(); | ||
| 126 | } | ||
| 127 | |||
| 128 | void UnbindCompute() { | ||
| 129 | if (is_compute_bound) { | ||
| 130 | is_compute_bound = false; | ||
| 131 | glUseProgram(0); | ||
| 132 | } | ||
| 133 | } | ||
| 134 | 39 | ||
| 135 | OGLPipeline pipeline; | 40 | OGLPipeline pipeline; |
| 136 | bool is_pipeline_bound{}; | 41 | bool is_pipeline_bound{}; |
diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp index 3f2b139e0..dd00d3edf 100644 --- a/src/video_core/renderer_vulkan/blit_image.cpp +++ b/src/video_core/renderer_vulkan/blit_image.cpp | |||
| @@ -4,13 +4,13 @@ | |||
| 4 | #include <algorithm> | 4 | #include <algorithm> |
| 5 | 5 | ||
| 6 | #include "common/settings.h" | 6 | #include "common/settings.h" |
| 7 | #include "video_core/host_shaders/blit_color_float_frag_spv.h" | ||
| 7 | #include "video_core/host_shaders/convert_abgr8_to_d24s8_frag_spv.h" | 8 | #include "video_core/host_shaders/convert_abgr8_to_d24s8_frag_spv.h" |
| 8 | #include "video_core/host_shaders/convert_d24s8_to_abgr8_frag_spv.h" | 9 | #include "video_core/host_shaders/convert_d24s8_to_abgr8_frag_spv.h" |
| 9 | #include "video_core/host_shaders/convert_depth_to_float_frag_spv.h" | 10 | #include "video_core/host_shaders/convert_depth_to_float_frag_spv.h" |
| 10 | #include "video_core/host_shaders/convert_float_to_depth_frag_spv.h" | 11 | #include "video_core/host_shaders/convert_float_to_depth_frag_spv.h" |
| 11 | #include "video_core/host_shaders/convert_s8d24_to_abgr8_frag_spv.h" | 12 | #include "video_core/host_shaders/convert_s8d24_to_abgr8_frag_spv.h" |
| 12 | #include "video_core/host_shaders/full_screen_triangle_vert_spv.h" | 13 | #include "video_core/host_shaders/full_screen_triangle_vert_spv.h" |
| 13 | #include "video_core/host_shaders/vulkan_blit_color_float_frag_spv.h" | ||
| 14 | #include "video_core/host_shaders/vulkan_blit_depth_stencil_frag_spv.h" | 14 | #include "video_core/host_shaders/vulkan_blit_depth_stencil_frag_spv.h" |
| 15 | #include "video_core/renderer_vulkan/blit_image.h" | 15 | #include "video_core/renderer_vulkan/blit_image.h" |
| 16 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" | 16 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" |
| @@ -303,7 +303,7 @@ void UpdateTwoTexturesDescriptorSet(const Device& device, VkDescriptorSet descri | |||
| 303 | } | 303 | } |
| 304 | 304 | ||
| 305 | void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, const Region2D& dst_region, | 305 | void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, const Region2D& dst_region, |
| 306 | const Region2D& src_region) { | 306 | const Region2D& src_region, const Extent3D& src_size = {1, 1, 1}) { |
| 307 | const VkOffset2D offset{ | 307 | const VkOffset2D offset{ |
| 308 | .x = std::min(dst_region.start.x, dst_region.end.x), | 308 | .x = std::min(dst_region.start.x, dst_region.end.x), |
| 309 | .y = std::min(dst_region.start.y, dst_region.end.y), | 309 | .y = std::min(dst_region.start.y, dst_region.end.y), |
| @@ -325,12 +325,15 @@ void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, const Regi | |||
| 325 | .offset = offset, | 325 | .offset = offset, |
| 326 | .extent = extent, | 326 | .extent = extent, |
| 327 | }; | 327 | }; |
| 328 | const float scale_x = static_cast<float>(src_region.end.x - src_region.start.x); | 328 | const float scale_x = static_cast<float>(src_region.end.x - src_region.start.x) / |
| 329 | const float scale_y = static_cast<float>(src_region.end.y - src_region.start.y); | 329 | static_cast<float>(src_size.width); |
| 330 | const float scale_y = static_cast<float>(src_region.end.y - src_region.start.y) / | ||
| 331 | static_cast<float>(src_size.height); | ||
| 330 | const PushConstants push_constants{ | 332 | const PushConstants push_constants{ |
| 331 | .tex_scale = {scale_x, scale_y}, | 333 | .tex_scale = {scale_x, scale_y}, |
| 332 | .tex_offset = {static_cast<float>(src_region.start.x), | 334 | .tex_offset = {static_cast<float>(src_region.start.x) / static_cast<float>(src_size.width), |
| 333 | static_cast<float>(src_region.start.y)}, | 335 | static_cast<float>(src_region.start.y) / |
| 336 | static_cast<float>(src_size.height)}, | ||
| 334 | }; | 337 | }; |
| 335 | cmdbuf.SetViewport(0, viewport); | 338 | cmdbuf.SetViewport(0, viewport); |
| 336 | cmdbuf.SetScissor(0, scissor); | 339 | cmdbuf.SetScissor(0, scissor); |
| @@ -347,6 +350,51 @@ VkExtent2D GetConversionExtent(const ImageView& src_image_view) { | |||
| 347 | .height = is_rescaled ? resolution.ScaleUp(height) : height, | 350 | .height = is_rescaled ? resolution.ScaleUp(height) : height, |
| 348 | }; | 351 | }; |
| 349 | } | 352 | } |
| 353 | |||
| 354 | void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayout target_layout, | ||
| 355 | VkImageLayout source_layout = VK_IMAGE_LAYOUT_GENERAL) { | ||
| 356 | constexpr VkFlags flags{VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | | ||
| 357 | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT}; | ||
| 358 | const VkImageMemoryBarrier barrier{ | ||
| 359 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 360 | .pNext = nullptr, | ||
| 361 | .srcAccessMask = flags, | ||
| 362 | .dstAccessMask = flags, | ||
| 363 | .oldLayout = source_layout, | ||
| 364 | .newLayout = target_layout, | ||
| 365 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 366 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 367 | .image = image, | ||
| 368 | .subresourceRange{ | ||
| 369 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||
| 370 | .baseMipLevel = 0, | ||
| 371 | .levelCount = 1, | ||
| 372 | .baseArrayLayer = 0, | ||
| 373 | .layerCount = 1, | ||
| 374 | }, | ||
| 375 | }; | ||
| 376 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, | ||
| 377 | 0, barrier); | ||
| 378 | } | ||
| 379 | |||
| 380 | void BeginRenderPass(vk::CommandBuffer& cmdbuf, const Framebuffer* framebuffer) { | ||
| 381 | const VkRenderPass render_pass = framebuffer->RenderPass(); | ||
| 382 | const VkFramebuffer framebuffer_handle = framebuffer->Handle(); | ||
| 383 | const VkExtent2D render_area = framebuffer->RenderArea(); | ||
| 384 | const VkRenderPassBeginInfo renderpass_bi{ | ||
| 385 | .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, | ||
| 386 | .pNext = nullptr, | ||
| 387 | .renderPass = render_pass, | ||
| 388 | .framebuffer = framebuffer_handle, | ||
| 389 | .renderArea{ | ||
| 390 | .offset{}, | ||
| 391 | .extent = render_area, | ||
| 392 | }, | ||
| 393 | .clearValueCount = 0, | ||
| 394 | .pClearValues = nullptr, | ||
| 395 | }; | ||
| 396 | cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE); | ||
| 397 | } | ||
| 350 | } // Anonymous namespace | 398 | } // Anonymous namespace |
| 351 | 399 | ||
| 352 | BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_, | 400 | BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_, |
| @@ -365,7 +413,7 @@ BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_, | |||
| 365 | two_textures_pipeline_layout(device.GetLogical().CreatePipelineLayout( | 413 | two_textures_pipeline_layout(device.GetLogical().CreatePipelineLayout( |
| 366 | PipelineLayoutCreateInfo(two_textures_set_layout.address()))), | 414 | PipelineLayoutCreateInfo(two_textures_set_layout.address()))), |
| 367 | full_screen_vert(BuildShader(device, FULL_SCREEN_TRIANGLE_VERT_SPV)), | 415 | full_screen_vert(BuildShader(device, FULL_SCREEN_TRIANGLE_VERT_SPV)), |
| 368 | blit_color_to_color_frag(BuildShader(device, VULKAN_BLIT_COLOR_FLOAT_FRAG_SPV)), | 416 | blit_color_to_color_frag(BuildShader(device, BLIT_COLOR_FLOAT_FRAG_SPV)), |
| 369 | blit_depth_stencil_frag(BuildShader(device, VULKAN_BLIT_DEPTH_STENCIL_FRAG_SPV)), | 417 | blit_depth_stencil_frag(BuildShader(device, VULKAN_BLIT_DEPTH_STENCIL_FRAG_SPV)), |
| 370 | convert_depth_to_float_frag(BuildShader(device, CONVERT_DEPTH_TO_FLOAT_FRAG_SPV)), | 418 | convert_depth_to_float_frag(BuildShader(device, CONVERT_DEPTH_TO_FLOAT_FRAG_SPV)), |
| 371 | convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)), | 419 | convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)), |
| @@ -404,6 +452,32 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView | |||
| 404 | scheduler.InvalidateState(); | 452 | scheduler.InvalidateState(); |
| 405 | } | 453 | } |
| 406 | 454 | ||
| 455 | void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView src_image_view, | ||
| 456 | VkImage src_image, VkSampler src_sampler, | ||
| 457 | const Region2D& dst_region, const Region2D& src_region, | ||
| 458 | const Extent3D& src_size) { | ||
| 459 | const BlitImagePipelineKey key{ | ||
| 460 | .renderpass = dst_framebuffer->RenderPass(), | ||
| 461 | .operation = Tegra::Engines::Fermi2D::Operation::SrcCopy, | ||
| 462 | }; | ||
| 463 | const VkPipelineLayout layout = *one_texture_pipeline_layout; | ||
| 464 | const VkPipeline pipeline = FindOrEmplaceColorPipeline(key); | ||
| 465 | scheduler.RequestOutsideRenderPassOperationContext(); | ||
| 466 | scheduler.Record([this, dst_framebuffer, src_image_view, src_image, src_sampler, dst_region, | ||
| 467 | src_region, src_size, pipeline, layout](vk::CommandBuffer cmdbuf) { | ||
| 468 | TransitionImageLayout(cmdbuf, src_image, VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL); | ||
| 469 | BeginRenderPass(cmdbuf, dst_framebuffer); | ||
| 470 | const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit(); | ||
| 471 | UpdateOneTextureDescriptorSet(device, descriptor_set, src_sampler, src_image_view); | ||
| 472 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); | ||
| 473 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set, | ||
| 474 | nullptr); | ||
| 475 | BindBlitState(cmdbuf, layout, dst_region, src_region, src_size); | ||
| 476 | cmdbuf.Draw(3, 1, 0, 0); | ||
| 477 | cmdbuf.EndRenderPass(); | ||
| 478 | }); | ||
| 479 | } | ||
| 480 | |||
| 407 | void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer, | 481 | void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer, |
| 408 | VkImageView src_depth_view, VkImageView src_stencil_view, | 482 | VkImageView src_depth_view, VkImageView src_stencil_view, |
| 409 | const Region2D& dst_region, const Region2D& src_region, | 483 | const Region2D& dst_region, const Region2D& src_region, |
diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h index 5df679fb4..be8a9a2f6 100644 --- a/src/video_core/renderer_vulkan/blit_image.h +++ b/src/video_core/renderer_vulkan/blit_image.h | |||
| @@ -10,6 +10,8 @@ | |||
| 10 | 10 | ||
| 11 | namespace Vulkan { | 11 | namespace Vulkan { |
| 12 | 12 | ||
| 13 | using VideoCommon::Extent3D; | ||
| 14 | using VideoCommon::Offset2D; | ||
| 13 | using VideoCommon::Region2D; | 15 | using VideoCommon::Region2D; |
| 14 | 16 | ||
| 15 | class Device; | 17 | class Device; |
| @@ -36,6 +38,10 @@ public: | |||
| 36 | Tegra::Engines::Fermi2D::Filter filter, | 38 | Tegra::Engines::Fermi2D::Filter filter, |
| 37 | Tegra::Engines::Fermi2D::Operation operation); | 39 | Tegra::Engines::Fermi2D::Operation operation); |
| 38 | 40 | ||
| 41 | void BlitColor(const Framebuffer* dst_framebuffer, VkImageView src_image_view, | ||
| 42 | VkImage src_image, VkSampler src_sampler, const Region2D& dst_region, | ||
| 43 | const Region2D& src_region, const Extent3D& src_size); | ||
| 44 | |||
| 39 | void BlitDepthStencil(const Framebuffer* dst_framebuffer, VkImageView src_depth_view, | 45 | void BlitDepthStencil(const Framebuffer* dst_framebuffer, VkImageView src_depth_view, |
| 40 | VkImageView src_stencil_view, const Region2D& dst_region, | 46 | VkImageView src_stencil_view, const Region2D& dst_region, |
| 41 | const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter, | 47 | const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter, |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index b75b8eec6..86ef0daeb 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp | |||
| @@ -266,6 +266,35 @@ void RasterizerVulkan::DrawIndirect() { | |||
| 266 | buffer_cache.SetDrawIndirect(nullptr); | 266 | buffer_cache.SetDrawIndirect(nullptr); |
| 267 | } | 267 | } |
| 268 | 268 | ||
| 269 | void RasterizerVulkan::DrawTexture() { | ||
| 270 | MICROPROFILE_SCOPE(Vulkan_Drawing); | ||
| 271 | |||
| 272 | SCOPE_EXIT({ gpu.TickWork(); }); | ||
| 273 | FlushWork(); | ||
| 274 | |||
| 275 | query_cache.UpdateCounters(); | ||
| 276 | |||
| 277 | texture_cache.SynchronizeGraphicsDescriptors(); | ||
| 278 | texture_cache.UpdateRenderTargets(false); | ||
| 279 | |||
| 280 | UpdateDynamicStates(); | ||
| 281 | |||
| 282 | const auto& draw_texture_state = maxwell3d->draw_manager->GetDrawTextureState(); | ||
| 283 | const auto& sampler = texture_cache.GetGraphicsSampler(draw_texture_state.src_sampler); | ||
| 284 | const auto& texture = texture_cache.GetImageView(draw_texture_state.src_texture); | ||
| 285 | Region2D dst_region = {Offset2D{.x = static_cast<s32>(draw_texture_state.dst_x0), | ||
| 286 | .y = static_cast<s32>(draw_texture_state.dst_y0)}, | ||
| 287 | Offset2D{.x = static_cast<s32>(draw_texture_state.dst_x1), | ||
| 288 | .y = static_cast<s32>(draw_texture_state.dst_y1)}}; | ||
| 289 | Region2D src_region = {Offset2D{.x = static_cast<s32>(draw_texture_state.src_x0), | ||
| 290 | .y = static_cast<s32>(draw_texture_state.src_y0)}, | ||
| 291 | Offset2D{.x = static_cast<s32>(draw_texture_state.src_x1), | ||
| 292 | .y = static_cast<s32>(draw_texture_state.src_y1)}}; | ||
| 293 | blit_image.BlitColor(texture_cache.GetFramebuffer(), texture.RenderTarget(), | ||
| 294 | texture.ImageHandle(), sampler->Handle(), dst_region, src_region, | ||
| 295 | texture.size); | ||
| 296 | } | ||
| 297 | |||
| 269 | void RasterizerVulkan::Clear(u32 layer_count) { | 298 | void RasterizerVulkan::Clear(u32 layer_count) { |
| 270 | MICROPROFILE_SCOPE(Vulkan_Clearing); | 299 | MICROPROFILE_SCOPE(Vulkan_Clearing); |
| 271 | 300 | ||
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index 472cc64d9..a0508b57c 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h | |||
| @@ -66,6 +66,7 @@ public: | |||
| 66 | 66 | ||
| 67 | void Draw(bool is_indexed, u32 instance_count) override; | 67 | void Draw(bool is_indexed, u32 instance_count) override; |
| 68 | void DrawIndirect() override; | 68 | void DrawIndirect() override; |
| 69 | void DrawTexture() override; | ||
| 69 | void Clear(u32 layer_count) override; | 70 | void Clear(u32 layer_count) override; |
| 70 | void DispatchCompute() override; | 71 | void DispatchCompute() override; |
| 71 | void ResetCounter(VideoCore::QueryType type) override; | 72 | void ResetCounter(VideoCore::QueryType type) override; |
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 87152c8e9..1b01990a4 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h | |||
| @@ -149,6 +149,13 @@ typename P::ImageView& TextureCache<P>::GetImageView(ImageViewId id) noexcept { | |||
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | template <class P> | 151 | template <class P> |
| 152 | typename P::ImageView& TextureCache<P>::GetImageView(u32 index) noexcept { | ||
| 153 | const auto image_view_id = VisitImageView(channel_state->graphics_image_table, | ||
| 154 | channel_state->graphics_image_view_ids, index); | ||
| 155 | return slot_image_views[image_view_id]; | ||
| 156 | } | ||
| 157 | |||
| 158 | template <class P> | ||
| 152 | void TextureCache<P>::MarkModification(ImageId id) noexcept { | 159 | void TextureCache<P>::MarkModification(ImageId id) noexcept { |
| 153 | MarkModification(slot_images[id]); | 160 | MarkModification(slot_images[id]); |
| 154 | } | 161 | } |
diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h index 4eea1f609..485eaabaa 100644 --- a/src/video_core/texture_cache/texture_cache_base.h +++ b/src/video_core/texture_cache/texture_cache_base.h | |||
| @@ -129,6 +129,9 @@ public: | |||
| 129 | /// Return a reference to the given image view id | 129 | /// Return a reference to the given image view id |
| 130 | [[nodiscard]] ImageView& GetImageView(ImageViewId id) noexcept; | 130 | [[nodiscard]] ImageView& GetImageView(ImageViewId id) noexcept; |
| 131 | 131 | ||
| 132 | /// Get the imageview from the graphics descriptor table in the specified index | ||
| 133 | [[nodiscard]] ImageView& GetImageView(u32 index) noexcept; | ||
| 134 | |||
| 132 | /// Mark an image as modified from the GPU | 135 | /// Mark an image as modified from the GPU |
| 133 | void MarkModification(ImageId id) noexcept; | 136 | void MarkModification(ImageId id) noexcept; |
| 134 | 137 | ||