summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/assert.h7
-rw-r--r--src/video_core/CMakeLists.txt5
-rw-r--r--src/video_core/host_shaders/CMakeLists.txt43
-rw-r--r--src/video_core/host_shaders/StringShaderHeader.cmake11
-rw-r--r--src/video_core/host_shaders/opengl_present.frag10
-rw-r--r--src/video_core/host_shaders/opengl_present.vert24
-rw-r--r--src/video_core/host_shaders/source_shader.h.in9
-rw-r--r--src/video_core/memory_manager.h34
-rw-r--r--src/video_core/renderer_opengl/gl_resource_manager.cpp9
-rw-r--r--src/video_core/renderer_opengl/gl_resource_manager.h3
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp1
-rw-r--r--src/video_core/renderer_opengl/gl_shader_util.cpp15
-rw-r--r--src/video_core/renderer_opengl/gl_shader_util.h2
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp46
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp4
-rw-r--r--src/video_core/renderer_vulkan/vk_state_tracker.cpp7
-rw-r--r--src/video_core/renderer_vulkan/vk_state_tracker.h16
-rw-r--r--src/video_core/shader/decode/memory.cpp3
18 files changed, 164 insertions, 85 deletions
diff --git a/src/common/assert.h b/src/common/assert.h
index 5b67c5c52..06d7b5612 100644
--- a/src/common/assert.h
+++ b/src/common/assert.h
@@ -17,11 +17,12 @@
17// enough for our purposes. 17// enough for our purposes.
18template <typename Fn> 18template <typename Fn>
19#if defined(_MSC_VER) 19#if defined(_MSC_VER)
20__declspec(noinline, noreturn) 20[[msvc::noinline, noreturn]]
21#elif defined(__GNUC__) 21#elif defined(__GNUC__)
22 __attribute__((noinline, noreturn, cold)) 22[[gnu::cold, gnu::noinline, noreturn]]
23#endif 23#endif
24 static void assert_noinline_call(const Fn& fn) { 24static void
25assert_noinline_call(const Fn& fn) {
25 fn(); 26 fn();
26 Crash(); 27 Crash();
27 exit(1); // Keeps GCC's mouth shut about this actually returning 28 exit(1); // Keeps GCC's mouth shut about this actually returning
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 3cd896a0f..d85f1e9d1 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -1,3 +1,5 @@
1add_subdirectory(host_shaders)
2
1add_library(video_core STATIC 3add_library(video_core STATIC
2 buffer_cache/buffer_block.h 4 buffer_cache/buffer_block.h
3 buffer_cache/buffer_cache.h 5 buffer_cache/buffer_cache.h
@@ -244,6 +246,9 @@ create_target_directory_groups(video_core)
244target_link_libraries(video_core PUBLIC common core) 246target_link_libraries(video_core PUBLIC common core)
245target_link_libraries(video_core PRIVATE glad xbyak) 247target_link_libraries(video_core PRIVATE glad xbyak)
246 248
249add_dependencies(video_core host_shaders)
250target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE})
251
247if (ENABLE_VULKAN) 252if (ENABLE_VULKAN)
248 target_include_directories(video_core PRIVATE sirit ../../externals/Vulkan-Headers/include) 253 target_include_directories(video_core PRIVATE sirit ../../externals/Vulkan-Headers/include)
249 target_compile_definitions(video_core PRIVATE HAS_VULKAN) 254 target_compile_definitions(video_core PRIVATE HAS_VULKAN)
diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt
new file mode 100644
index 000000000..aa62363a7
--- /dev/null
+++ b/src/video_core/host_shaders/CMakeLists.txt
@@ -0,0 +1,43 @@
1set(SHADER_FILES
2 opengl_present.frag
3 opengl_present.vert
4)
5
6set(SHADER_INCLUDE ${CMAKE_CURRENT_BINARY_DIR}/include)
7set(HOST_SHADERS_INCLUDE ${SHADER_INCLUDE} PARENT_SCOPE)
8
9set(SHADER_DIR ${SHADER_INCLUDE}/video_core/host_shaders)
10add_custom_command(
11 OUTPUT
12 ${SHADER_DIR}
13 COMMAND
14 ${CMAKE_COMMAND} -E make_directory ${SHADER_DIR}
15)
16
17set(INPUT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/source_shader.h.in)
18set(HEADER_GENERATOR ${CMAKE_CURRENT_SOURCE_DIR}/StringShaderHeader.cmake)
19
20foreach(FILENAME IN ITEMS ${SHADER_FILES})
21 string(REPLACE "." "_" SHADER_NAME ${FILENAME})
22 set(SOURCE_FILE ${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME})
23 set(HEADER_FILE ${SHADER_DIR}/${SHADER_NAME}.h)
24 add_custom_command(
25 OUTPUT
26 ${HEADER_FILE}
27 COMMAND
28 ${CMAKE_COMMAND} -P ${HEADER_GENERATOR} ${SOURCE_FILE} ${HEADER_FILE} ${INPUT_FILE}
29 MAIN_DEPENDENCY
30 ${SOURCE_FILE}
31 DEPENDS
32 ${HEADER_GENERATOR}
33 ${INPUT_FILE}
34 )
35 set(SHADER_HEADERS ${SHADER_HEADERS} ${HEADER_FILE})
36endforeach()
37
38add_custom_target(host_shaders
39 DEPENDS
40 ${SHADER_HEADERS}
41 SOURCES
42 ${SHADER_FILES}
43)
diff --git a/src/video_core/host_shaders/StringShaderHeader.cmake b/src/video_core/host_shaders/StringShaderHeader.cmake
new file mode 100644
index 000000000..368bce0ed
--- /dev/null
+++ b/src/video_core/host_shaders/StringShaderHeader.cmake
@@ -0,0 +1,11 @@
1set(SOURCE_FILE ${CMAKE_ARGV3})
2set(HEADER_FILE ${CMAKE_ARGV4})
3set(INPUT_FILE ${CMAKE_ARGV5})
4
5get_filename_component(CONTENTS_NAME ${SOURCE_FILE} NAME)
6string(REPLACE "." "_" CONTENTS_NAME ${CONTENTS_NAME})
7string(TOUPPER ${CONTENTS_NAME} CONTENTS_NAME)
8
9file(READ ${SOURCE_FILE} CONTENTS)
10
11configure_file(${INPUT_FILE} ${HEADER_FILE} @ONLY)
diff --git a/src/video_core/host_shaders/opengl_present.frag b/src/video_core/host_shaders/opengl_present.frag
new file mode 100644
index 000000000..8a4cb024b
--- /dev/null
+++ b/src/video_core/host_shaders/opengl_present.frag
@@ -0,0 +1,10 @@
1#version 430 core
2
3layout (location = 0) in vec2 frag_tex_coord;
4layout (location = 0) out vec4 color;
5
6layout (binding = 0) uniform sampler2D color_texture;
7
8void main() {
9 color = vec4(texture(color_texture, frag_tex_coord).rgb, 1.0f);
10}
diff --git a/src/video_core/host_shaders/opengl_present.vert b/src/video_core/host_shaders/opengl_present.vert
new file mode 100644
index 000000000..2235d31a4
--- /dev/null
+++ b/src/video_core/host_shaders/opengl_present.vert
@@ -0,0 +1,24 @@
1#version 430 core
2
3out gl_PerVertex {
4 vec4 gl_Position;
5};
6
7layout (location = 0) in vec2 vert_position;
8layout (location = 1) in vec2 vert_tex_coord;
9layout (location = 0) out vec2 frag_tex_coord;
10
11// This is a truncated 3x3 matrix for 2D transformations:
12// The upper-left 2x2 submatrix performs scaling/rotation/mirroring.
13// The third column performs translation.
14// The third row could be used for projection, which we don't need in 2D. It hence is assumed to
15// implicitly be [0, 0, 1]
16layout (location = 0) uniform mat3x2 modelview_matrix;
17
18void main() {
19 // Multiply input position by the rotscale part of the matrix and then manually translate by
20 // the last column. This is equivalent to using a full 3x3 matrix and expanding the vector
21 // to `vec3(vert_position.xy, 1.0)`
22 gl_Position = vec4(mat2(modelview_matrix) * vert_position + modelview_matrix[2], 0.0, 1.0);
23 frag_tex_coord = vert_tex_coord;
24}
diff --git a/src/video_core/host_shaders/source_shader.h.in b/src/video_core/host_shaders/source_shader.h.in
new file mode 100644
index 000000000..ccdb0d2a9
--- /dev/null
+++ b/src/video_core/host_shaders/source_shader.h.in
@@ -0,0 +1,9 @@
1#pragma once
2
3#include <string_view>
4
5namespace HostShaders {
6
7constexpr std::string_view @CONTENTS_NAME@ = R"(@CONTENTS@)";
8
9} // namespace HostShaders
diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h
index 533b415e9..53c8d122a 100644
--- a/src/video_core/memory_manager.h
+++ b/src/video_core/memory_manager.h
@@ -31,19 +31,19 @@ public:
31 constexpr PageEntry(State state) : state{state} {} 31 constexpr PageEntry(State state) : state{state} {}
32 constexpr PageEntry(VAddr addr) : state{static_cast<State>(addr >> ShiftBits)} {} 32 constexpr PageEntry(VAddr addr) : state{static_cast<State>(addr >> ShiftBits)} {}
33 33
34 constexpr bool IsUnmapped() const { 34 [[nodiscard]] constexpr bool IsUnmapped() const {
35 return state == State::Unmapped; 35 return state == State::Unmapped;
36 } 36 }
37 37
38 constexpr bool IsAllocated() const { 38 [[nodiscard]] constexpr bool IsAllocated() const {
39 return state == State::Allocated; 39 return state == State::Allocated;
40 } 40 }
41 41
42 constexpr bool IsValid() const { 42 [[nodiscard]] constexpr bool IsValid() const {
43 return !IsUnmapped() && !IsAllocated(); 43 return !IsUnmapped() && !IsAllocated();
44 } 44 }
45 45
46 constexpr VAddr ToAddress() const { 46 [[nodiscard]] constexpr VAddr ToAddress() const {
47 if (!IsValid()) { 47 if (!IsValid()) {
48 return {}; 48 return {};
49 } 49 }
@@ -51,7 +51,7 @@ public:
51 return static_cast<VAddr>(state) << ShiftBits; 51 return static_cast<VAddr>(state) << ShiftBits;
52 } 52 }
53 53
54 constexpr PageEntry operator+(u64 offset) { 54 [[nodiscard]] constexpr PageEntry operator+(u64 offset) const {
55 // If this is a reserved value, offsets do not apply 55 // If this is a reserved value, offsets do not apply
56 if (!IsValid()) { 56 if (!IsValid()) {
57 return *this; 57 return *this;
@@ -74,16 +74,16 @@ public:
74 /// Binds a renderer to the memory manager. 74 /// Binds a renderer to the memory manager.
75 void BindRasterizer(VideoCore::RasterizerInterface& rasterizer); 75 void BindRasterizer(VideoCore::RasterizerInterface& rasterizer);
76 76
77 std::optional<VAddr> GpuToCpuAddress(GPUVAddr addr) const; 77 [[nodiscard]] std::optional<VAddr> GpuToCpuAddress(GPUVAddr addr) const;
78 78
79 template <typename T> 79 template <typename T>
80 T Read(GPUVAddr addr) const; 80 [[nodiscard]] T Read(GPUVAddr addr) const;
81 81
82 template <typename T> 82 template <typename T>
83 void Write(GPUVAddr addr, T data); 83 void Write(GPUVAddr addr, T data);
84 84
85 u8* GetPointer(GPUVAddr addr); 85 [[nodiscard]] u8* GetPointer(GPUVAddr addr);
86 const u8* GetPointer(GPUVAddr addr) const; 86 [[nodiscard]] const u8* GetPointer(GPUVAddr addr) const;
87 87
88 /** 88 /**
89 * ReadBlock and WriteBlock are full read and write operations over virtual 89 * ReadBlock and WriteBlock are full read and write operations over virtual
@@ -112,24 +112,24 @@ public:
112 /** 112 /**
113 * IsGranularRange checks if a gpu region can be simply read with a pointer. 113 * IsGranularRange checks if a gpu region can be simply read with a pointer.
114 */ 114 */
115 bool IsGranularRange(GPUVAddr gpu_addr, std::size_t size) const; 115 [[nodiscard]] bool IsGranularRange(GPUVAddr gpu_addr, std::size_t size) const;
116 116
117 GPUVAddr Map(VAddr cpu_addr, GPUVAddr gpu_addr, std::size_t size); 117 [[nodiscard]] GPUVAddr Map(VAddr cpu_addr, GPUVAddr gpu_addr, std::size_t size);
118 GPUVAddr MapAllocate(VAddr cpu_addr, std::size_t size, std::size_t align); 118 [[nodiscard]] GPUVAddr MapAllocate(VAddr cpu_addr, std::size_t size, std::size_t align);
119 std::optional<GPUVAddr> AllocateFixed(GPUVAddr gpu_addr, std::size_t size); 119 [[nodiscard]] std::optional<GPUVAddr> AllocateFixed(GPUVAddr gpu_addr, std::size_t size);
120 GPUVAddr Allocate(std::size_t size, std::size_t align); 120 [[nodiscard]] GPUVAddr Allocate(std::size_t size, std::size_t align);
121 void Unmap(GPUVAddr gpu_addr, std::size_t size); 121 void Unmap(GPUVAddr gpu_addr, std::size_t size);
122 122
123private: 123private:
124 PageEntry GetPageEntry(GPUVAddr gpu_addr) const; 124 [[nodiscard]] PageEntry GetPageEntry(GPUVAddr gpu_addr) const;
125 void SetPageEntry(GPUVAddr gpu_addr, PageEntry page_entry, std::size_t size = page_size); 125 void SetPageEntry(GPUVAddr gpu_addr, PageEntry page_entry, std::size_t size = page_size);
126 GPUVAddr UpdateRange(GPUVAddr gpu_addr, PageEntry page_entry, std::size_t size); 126 GPUVAddr UpdateRange(GPUVAddr gpu_addr, PageEntry page_entry, std::size_t size);
127 std::optional<GPUVAddr> FindFreeRange(std::size_t size, std::size_t align) const; 127 [[nodiscard]] std::optional<GPUVAddr> FindFreeRange(std::size_t size, std::size_t align) const;
128 128
129 void TryLockPage(PageEntry page_entry, std::size_t size); 129 void TryLockPage(PageEntry page_entry, std::size_t size);
130 void TryUnlockPage(PageEntry page_entry, std::size_t size); 130 void TryUnlockPage(PageEntry page_entry, std::size_t size);
131 131
132 static constexpr std::size_t PageEntryIndex(GPUVAddr gpu_addr) { 132 [[nodiscard]] static constexpr std::size_t PageEntryIndex(GPUVAddr gpu_addr) {
133 return (gpu_addr >> page_bits) & page_table_mask; 133 return (gpu_addr >> page_bits) & page_table_mask;
134 } 134 }
135 135
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.cpp b/src/video_core/renderer_opengl/gl_resource_manager.cpp
index a787e27d2..0ebcec427 100644
--- a/src/video_core/renderer_opengl/gl_resource_manager.cpp
+++ b/src/video_core/renderer_opengl/gl_resource_manager.cpp
@@ -2,6 +2,7 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <string_view>
5#include <utility> 6#include <utility>
6#include <glad/glad.h> 7#include <glad/glad.h>
7#include "common/common_types.h" 8#include "common/common_types.h"
@@ -82,11 +83,13 @@ void OGLSampler::Release() {
82 handle = 0; 83 handle = 0;
83} 84}
84 85
85void OGLShader::Create(const char* source, GLenum type) { 86void OGLShader::Create(std::string_view source, GLenum type) {
86 if (handle != 0) 87 if (handle != 0) {
87 return; 88 return;
88 if (source == nullptr) 89 }
90 if (source.empty()) {
89 return; 91 return;
92 }
90 93
91 MICROPROFILE_SCOPE(OpenGL_ResourceCreation); 94 MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
92 handle = GLShader::LoadShader(source, type); 95 handle = GLShader::LoadShader(source, type);
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.h b/src/video_core/renderer_opengl/gl_resource_manager.h
index b05cb641c..f48398669 100644
--- a/src/video_core/renderer_opengl/gl_resource_manager.h
+++ b/src/video_core/renderer_opengl/gl_resource_manager.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <string_view>
7#include <utility> 8#include <utility>
8#include <glad/glad.h> 9#include <glad/glad.h>
9#include "common/common_types.h" 10#include "common/common_types.h"
@@ -127,7 +128,7 @@ public:
127 return *this; 128 return *this;
128 } 129 }
129 130
130 void Create(const char* source, GLenum type); 131 void Create(std::string_view source, GLenum type);
131 132
132 void Release(); 133 void Release();
133 134
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index eb49a36bf..a07d56ef0 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -22,6 +22,7 @@
22#include "video_core/memory_manager.h" 22#include "video_core/memory_manager.h"
23#include "video_core/renderer_opengl/gl_arb_decompiler.h" 23#include "video_core/renderer_opengl/gl_arb_decompiler.h"
24#include "video_core/renderer_opengl/gl_rasterizer.h" 24#include "video_core/renderer_opengl/gl_rasterizer.h"
25#include "video_core/renderer_opengl/gl_resource_manager.h"
25#include "video_core/renderer_opengl/gl_shader_cache.h" 26#include "video_core/renderer_opengl/gl_shader_cache.h"
26#include "video_core/renderer_opengl/gl_shader_decompiler.h" 27#include "video_core/renderer_opengl/gl_shader_decompiler.h"
27#include "video_core/renderer_opengl/gl_shader_disk_cache.h" 28#include "video_core/renderer_opengl/gl_shader_disk_cache.h"
diff --git a/src/video_core/renderer_opengl/gl_shader_util.cpp b/src/video_core/renderer_opengl/gl_shader_util.cpp
index 9e74eda0d..4bf0d6090 100644
--- a/src/video_core/renderer_opengl/gl_shader_util.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_util.cpp
@@ -2,6 +2,7 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <string_view>
5#include <vector> 6#include <vector>
6#include <glad/glad.h> 7#include <glad/glad.h>
7#include "common/assert.h" 8#include "common/assert.h"
@@ -11,7 +12,8 @@
11namespace OpenGL::GLShader { 12namespace OpenGL::GLShader {
12 13
13namespace { 14namespace {
14const char* GetStageDebugName(GLenum type) { 15
16std::string_view StageDebugName(GLenum type) {
15 switch (type) { 17 switch (type) {
16 case GL_VERTEX_SHADER: 18 case GL_VERTEX_SHADER:
17 return "vertex"; 19 return "vertex";
@@ -25,12 +27,17 @@ const char* GetStageDebugName(GLenum type) {
25 UNIMPLEMENTED(); 27 UNIMPLEMENTED();
26 return "unknown"; 28 return "unknown";
27} 29}
30
28} // Anonymous namespace 31} // Anonymous namespace
29 32
30GLuint LoadShader(const char* source, GLenum type) { 33GLuint LoadShader(std::string_view source, GLenum type) {
31 const char* debug_type = GetStageDebugName(type); 34 const std::string_view debug_type = StageDebugName(type);
32 const GLuint shader_id = glCreateShader(type); 35 const GLuint shader_id = glCreateShader(type);
33 glShaderSource(shader_id, 1, &source, nullptr); 36
37 const GLchar* source_string = source.data();
38 const GLint source_length = static_cast<GLint>(source.size());
39
40 glShaderSource(shader_id, 1, &source_string, &source_length);
34 LOG_DEBUG(Render_OpenGL, "Compiling {} shader...", debug_type); 41 LOG_DEBUG(Render_OpenGL, "Compiling {} shader...", debug_type);
35 glCompileShader(shader_id); 42 glCompileShader(shader_id);
36 43
diff --git a/src/video_core/renderer_opengl/gl_shader_util.h b/src/video_core/renderer_opengl/gl_shader_util.h
index 03b7548c2..1b770532e 100644
--- a/src/video_core/renderer_opengl/gl_shader_util.h
+++ b/src/video_core/renderer_opengl/gl_shader_util.h
@@ -38,7 +38,7 @@ void LogShaderSource(T... shaders) {
38 * @param source String of the GLSL shader program 38 * @param source String of the GLSL shader program
39 * @param type Type of the shader (GL_VERTEX_SHADER, GL_GEOMETRY_SHADER or GL_FRAGMENT_SHADER) 39 * @param type Type of the shader (GL_VERTEX_SHADER, GL_GEOMETRY_SHADER or GL_FRAGMENT_SHADER)
40 */ 40 */
41GLuint LoadShader(const char* source, GLenum type); 41GLuint LoadShader(std::string_view source, GLenum type);
42 42
43/** 43/**
44 * Utility function to create and compile an OpenGL GLSL shader program (vertex + fragment shader) 44 * Utility function to create and compile an OpenGL GLSL shader program (vertex + fragment shader)
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index c39663db7..b759c2dba 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -21,6 +21,8 @@
21#include "core/perf_stats.h" 21#include "core/perf_stats.h"
22#include "core/settings.h" 22#include "core/settings.h"
23#include "core/telemetry_session.h" 23#include "core/telemetry_session.h"
24#include "video_core/host_shaders/opengl_present_frag.h"
25#include "video_core/host_shaders/opengl_present_vert.h"
24#include "video_core/morton.h" 26#include "video_core/morton.h"
25#include "video_core/renderer_opengl/gl_rasterizer.h" 27#include "video_core/renderer_opengl/gl_rasterizer.h"
26#include "video_core/renderer_opengl/gl_shader_manager.h" 28#include "video_core/renderer_opengl/gl_shader_manager.h"
@@ -44,46 +46,6 @@ struct Frame {
44 bool is_srgb{}; /// Framebuffer is sRGB or RGB 46 bool is_srgb{}; /// Framebuffer is sRGB or RGB
45}; 47};
46 48
47constexpr char VERTEX_SHADER[] = R"(
48#version 430 core
49
50out gl_PerVertex {
51 vec4 gl_Position;
52};
53
54layout (location = 0) in vec2 vert_position;
55layout (location = 1) in vec2 vert_tex_coord;
56layout (location = 0) out vec2 frag_tex_coord;
57
58// This is a truncated 3x3 matrix for 2D transformations:
59// The upper-left 2x2 submatrix performs scaling/rotation/mirroring.
60// The third column performs translation.
61// The third row could be used for projection, which we don't need in 2D. It hence is assumed to
62// implicitly be [0, 0, 1]
63layout (location = 0) uniform mat3x2 modelview_matrix;
64
65void main() {
66 // Multiply input position by the rotscale part of the matrix and then manually translate by
67 // the last column. This is equivalent to using a full 3x3 matrix and expanding the vector
68 // to `vec3(vert_position.xy, 1.0)`
69 gl_Position = vec4(mat2(modelview_matrix) * vert_position + modelview_matrix[2], 0.0, 1.0);
70 frag_tex_coord = vert_tex_coord;
71}
72)";
73
74constexpr char FRAGMENT_SHADER[] = R"(
75#version 430 core
76
77layout (location = 0) in vec2 frag_tex_coord;
78layout (location = 0) out vec4 color;
79
80layout (binding = 0) uniform sampler2D color_texture;
81
82void main() {
83 color = vec4(texture(color_texture, frag_tex_coord).rgb, 1.0f);
84}
85)";
86
87constexpr GLint PositionLocation = 0; 49constexpr GLint PositionLocation = 0;
88constexpr GLint TexCoordLocation = 1; 50constexpr GLint TexCoordLocation = 1;
89constexpr GLint ModelViewMatrixLocation = 0; 51constexpr GLint ModelViewMatrixLocation = 0;
@@ -461,10 +423,10 @@ void RendererOpenGL::InitOpenGLObjects() {
461 423
462 // Create shader programs 424 // Create shader programs
463 OGLShader vertex_shader; 425 OGLShader vertex_shader;
464 vertex_shader.Create(VERTEX_SHADER, GL_VERTEX_SHADER); 426 vertex_shader.Create(HostShaders::OPENGL_PRESENT_VERT, GL_VERTEX_SHADER);
465 427
466 OGLShader fragment_shader; 428 OGLShader fragment_shader;
467 fragment_shader.Create(FRAGMENT_SHADER, GL_FRAGMENT_SHADER); 429 fragment_shader.Create(HostShaders::OPENGL_PRESENT_FRAG, GL_FRAGMENT_SHADER);
468 430
469 vertex_program.Create(true, false, vertex_shader.handle); 431 vertex_program.Create(true, false, vertex_shader.handle);
470 fragment_program.Create(true, false, fragment_shader.handle); 432 fragment_program.Create(true, false, fragment_shader.handle);
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index 936f76195..ff1b52eab 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -1443,10 +1443,10 @@ void RasterizerVulkan::UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs) {
1443} 1443}
1444 1444
1445void RasterizerVulkan::UpdatePrimitiveTopology(Tegra::Engines::Maxwell3D::Regs& regs) { 1445void RasterizerVulkan::UpdatePrimitiveTopology(Tegra::Engines::Maxwell3D::Regs& regs) {
1446 if (!state_tracker.TouchPrimitiveTopology()) { 1446 const Maxwell::PrimitiveTopology primitive_topology = regs.draw.topology.Value();
1447 if (!state_tracker.ChangePrimitiveTopology(primitive_topology)) {
1447 return; 1448 return;
1448 } 1449 }
1449 const Maxwell::PrimitiveTopology primitive_topology = regs.draw.topology.Value();
1450 scheduler.Record([this, primitive_topology](vk::CommandBuffer cmdbuf) { 1450 scheduler.Record([this, primitive_topology](vk::CommandBuffer cmdbuf) {
1451 cmdbuf.SetPrimitiveTopologyEXT(MaxwellToVK::PrimitiveTopology(device, primitive_topology)); 1451 cmdbuf.SetPrimitiveTopologyEXT(MaxwellToVK::PrimitiveTopology(device, primitive_topology));
1452 }); 1452 });
diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.cpp b/src/video_core/renderer_vulkan/vk_state_tracker.cpp
index 9151d9fb1..4bd1009f9 100644
--- a/src/video_core/renderer_vulkan/vk_state_tracker.cpp
+++ b/src/video_core/renderer_vulkan/vk_state_tracker.cpp
@@ -42,7 +42,6 @@ Flags MakeInvalidationFlags() {
42 flags[DepthWriteEnable] = true; 42 flags[DepthWriteEnable] = true;
43 flags[DepthCompareOp] = true; 43 flags[DepthCompareOp] = true;
44 flags[FrontFace] = true; 44 flags[FrontFace] = true;
45 flags[PrimitiveTopology] = true;
46 flags[StencilOp] = true; 45 flags[StencilOp] = true;
47 flags[StencilTestEnable] = true; 46 flags[StencilTestEnable] = true;
48 return flags; 47 return flags;
@@ -112,10 +111,6 @@ void SetupDirtyFrontFace(Tables& tables) {
112 table[OFF(screen_y_control)] = FrontFace; 111 table[OFF(screen_y_control)] = FrontFace;
113} 112}
114 113
115void SetupDirtyPrimitiveTopology(Tables& tables) {
116 tables[0][OFF(draw.topology)] = PrimitiveTopology;
117}
118
119void SetupDirtyStencilOp(Tables& tables) { 114void SetupDirtyStencilOp(Tables& tables) {
120 auto& table = tables[0]; 115 auto& table = tables[0];
121 table[OFF(stencil_front_op_fail)] = StencilOp; 116 table[OFF(stencil_front_op_fail)] = StencilOp;
@@ -156,13 +151,13 @@ void StateTracker::Initialize() {
156 SetupDirtyDepthWriteEnable(tables); 151 SetupDirtyDepthWriteEnable(tables);
157 SetupDirtyDepthCompareOp(tables); 152 SetupDirtyDepthCompareOp(tables);
158 SetupDirtyFrontFace(tables); 153 SetupDirtyFrontFace(tables);
159 SetupDirtyPrimitiveTopology(tables);
160 SetupDirtyStencilOp(tables); 154 SetupDirtyStencilOp(tables);
161 SetupDirtyStencilTestEnable(tables); 155 SetupDirtyStencilTestEnable(tables);
162} 156}
163 157
164void StateTracker::InvalidateCommandBufferState() { 158void StateTracker::InvalidateCommandBufferState() {
165 system.GPU().Maxwell3D().dirty.flags |= invalidation_flags; 159 system.GPU().Maxwell3D().dirty.flags |= invalidation_flags;
160 current_topology = INVALID_TOPOLOGY;
166} 161}
167 162
168} // namespace Vulkan 163} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.h b/src/video_core/renderer_vulkan/vk_state_tracker.h
index 54ca0d6c6..13a6ce786 100644
--- a/src/video_core/renderer_vulkan/vk_state_tracker.h
+++ b/src/video_core/renderer_vulkan/vk_state_tracker.h
@@ -32,7 +32,6 @@ enum : u8 {
32 DepthWriteEnable, 32 DepthWriteEnable,
33 DepthCompareOp, 33 DepthCompareOp,
34 FrontFace, 34 FrontFace,
35 PrimitiveTopology,
36 StencilOp, 35 StencilOp,
37 StencilTestEnable, 36 StencilTestEnable,
38 37
@@ -43,6 +42,8 @@ static_assert(Last <= std::numeric_limits<u8>::max());
43} // namespace Dirty 42} // namespace Dirty
44 43
45class StateTracker { 44class StateTracker {
45 using Maxwell = Tegra::Engines::Maxwell3D::Regs;
46
46public: 47public:
47 explicit StateTracker(Core::System& system); 48 explicit StateTracker(Core::System& system);
48 49
@@ -102,10 +103,6 @@ public:
102 return Exchange(Dirty::FrontFace, false); 103 return Exchange(Dirty::FrontFace, false);
103 } 104 }
104 105
105 bool TouchPrimitiveTopology() {
106 return Exchange(Dirty::PrimitiveTopology, false);
107 }
108
109 bool TouchStencilOp() { 106 bool TouchStencilOp() {
110 return Exchange(Dirty::StencilOp, false); 107 return Exchange(Dirty::StencilOp, false);
111 } 108 }
@@ -114,7 +111,15 @@ public:
114 return Exchange(Dirty::StencilTestEnable, false); 111 return Exchange(Dirty::StencilTestEnable, false);
115 } 112 }
116 113
114 bool ChangePrimitiveTopology(Maxwell::PrimitiveTopology new_topology) {
115 const bool has_changed = current_topology != new_topology;
116 current_topology = new_topology;
117 return has_changed;
118 }
119
117private: 120private:
121 static constexpr auto INVALID_TOPOLOGY = static_cast<Maxwell::PrimitiveTopology>(~0u);
122
118 bool Exchange(std::size_t id, bool new_value) const noexcept { 123 bool Exchange(std::size_t id, bool new_value) const noexcept {
119 auto& flags = system.GPU().Maxwell3D().dirty.flags; 124 auto& flags = system.GPU().Maxwell3D().dirty.flags;
120 const bool is_dirty = flags[id]; 125 const bool is_dirty = flags[id];
@@ -124,6 +129,7 @@ private:
124 129
125 Core::System& system; 130 Core::System& system;
126 Tegra::Engines::Maxwell3D::DirtyState::Flags invalidation_flags; 131 Tegra::Engines::Maxwell3D::DirtyState::Flags invalidation_flags;
132 Maxwell::PrimitiveTopology current_topology = INVALID_TOPOLOGY;
127}; 133};
128 134
129} // namespace Vulkan 135} // namespace Vulkan
diff --git a/src/video_core/shader/decode/memory.cpp b/src/video_core/shader/decode/memory.cpp
index e4739394d..e2bba88dd 100644
--- a/src/video_core/shader/decode/memory.cpp
+++ b/src/video_core/shader/decode/memory.cpp
@@ -386,7 +386,8 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
386 break; 386 break;
387 } 387 }
388 case OpCode::Id::RED: { 388 case OpCode::Id::RED: {
389 UNIMPLEMENTED_IF_MSG(instr.red.type != GlobalAtomicType::U32); 389 UNIMPLEMENTED_IF_MSG(instr.red.type != GlobalAtomicType::U32, "type={}",
390 static_cast<int>(instr.red.type.Value()));
390 const auto [real_address, base_address, descriptor] = 391 const auto [real_address, base_address, descriptor] =
391 TrackGlobalMemory(bb, instr, true, true); 392 TrackGlobalMemory(bb, instr, true, true);
392 if (!real_address || !base_address) { 393 if (!real_address || !base_address) {