summaryrefslogtreecommitdiff
path: root/src/video_core
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core')
-rw-r--r--src/video_core/CMakeLists.txt1
-rw-r--r--src/video_core/command_processor.cpp16
-rw-r--r--src/video_core/debug_utils/debug_utils.cpp44
-rw-r--r--src/video_core/debug_utils/debug_utils.h12
-rw-r--r--src/video_core/pica.cpp72
-rw-r--r--src/video_core/pica.h65
-rw-r--r--src/video_core/rasterizer.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_resource_manager.cpp111
-rw-r--r--src/video_core/renderer_opengl/gl_resource_manager.h110
-rw-r--r--src/video_core/vertex_shader.cpp59
10 files changed, 220 insertions, 272 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 5c7f4ae18..162108301 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -2,7 +2,6 @@ set(SRCS
2 renderer_opengl/generated/gl_3_2_core.c 2 renderer_opengl/generated/gl_3_2_core.c
3 renderer_opengl/gl_rasterizer.cpp 3 renderer_opengl/gl_rasterizer.cpp
4 renderer_opengl/gl_rasterizer_cache.cpp 4 renderer_opengl/gl_rasterizer_cache.cpp
5 renderer_opengl/gl_resource_manager.cpp
6 renderer_opengl/gl_shader_util.cpp 5 renderer_opengl/gl_shader_util.cpp
7 renderer_opengl/gl_state.cpp 6 renderer_opengl/gl_state.cpp
8 renderer_opengl/renderer_opengl.cpp 7 renderer_opengl/renderer_opengl.cpp
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
index bbe7e63dc..36c3b9947 100644
--- a/src/video_core/command_processor.cpp
+++ b/src/video_core/command_processor.cpp
@@ -50,7 +50,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
50 regs[id] = (old_value & ~mask) | (value & mask); 50 regs[id] = (old_value & ~mask) | (value & mask);
51 51
52 if (g_debug_context) 52 if (g_debug_context)
53 g_debug_context->OnEvent(DebugContext::Event::CommandLoaded, reinterpret_cast<void*>(&id)); 53 g_debug_context->OnEvent(DebugContext::Event::PicaCommandLoaded, reinterpret_cast<void*>(&id));
54 54
55 DebugUtils::OnPicaRegWrite(id, regs[id]); 55 DebugUtils::OnPicaRegWrite(id, regs[id]);
56 56
@@ -103,7 +103,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
103 case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[0], 0x23c): 103 case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[0], 0x23c):
104 case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[1], 0x23d): 104 case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[1], 0x23d):
105 { 105 {
106 unsigned index = id - PICA_REG_INDEX(command_buffer.trigger[0]); 106 unsigned index = static_cast<unsigned>(id - PICA_REG_INDEX(command_buffer.trigger[0]));
107 u32* head_ptr = (u32*)Memory::GetPhysicalPointer(regs.command_buffer.GetPhysicalAddress(index)); 107 u32* head_ptr = (u32*)Memory::GetPhysicalPointer(regs.command_buffer.GetPhysicalAddress(index));
108 g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = head_ptr; 108 g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = head_ptr;
109 g_state.cmd_list.length = regs.command_buffer.GetSize(index) / sizeof(u32); 109 g_state.cmd_list.length = regs.command_buffer.GetSize(index) / sizeof(u32);
@@ -116,7 +116,9 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
116 { 116 {
117 Common::Profiling::ScopeTimer scope_timer(category_drawing); 117 Common::Profiling::ScopeTimer scope_timer(category_drawing);
118 118
119#if PICA_LOG_TEV
119 DebugUtils::DumpTevStageConfig(regs.GetTevStages()); 120 DebugUtils::DumpTevStageConfig(regs.GetTevStages());
121#endif
120 122
121 if (g_debug_context) 123 if (g_debug_context)
122 g_debug_context->OnEvent(DebugContext::Event::IncomingPrimitiveBatch, nullptr); 124 g_debug_context->OnEvent(DebugContext::Event::IncomingPrimitiveBatch, nullptr);
@@ -159,9 +161,11 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
159 const u16* index_address_16 = (u16*)index_address_8; 161 const u16* index_address_16 = (u16*)index_address_8;
160 bool index_u16 = index_info.format != 0; 162 bool index_u16 = index_info.format != 0;
161 163
164#if PICA_DUMP_GEOMETRY
162 DebugUtils::GeometryDumper geometry_dumper; 165 DebugUtils::GeometryDumper geometry_dumper;
163 PrimitiveAssembler<VertexShader::OutputVertex> primitive_assembler(regs.triangle_topology.Value());
164 PrimitiveAssembler<DebugUtils::GeometryDumper::Vertex> dumping_primitive_assembler(regs.triangle_topology.Value()); 166 PrimitiveAssembler<DebugUtils::GeometryDumper::Vertex> dumping_primitive_assembler(regs.triangle_topology.Value());
167#endif
168 PrimitiveAssembler<VertexShader::OutputVertex> primitive_assembler(regs.triangle_topology.Value());
165 169
166 if (g_debug_context) { 170 if (g_debug_context) {
167 for (int i = 0; i < 3; ++i) { 171 for (int i = 0; i < 3; ++i) {
@@ -267,6 +271,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
267 if (g_debug_context) 271 if (g_debug_context)
268 g_debug_context->OnEvent(DebugContext::Event::VertexLoaded, (void*)&input); 272 g_debug_context->OnEvent(DebugContext::Event::VertexLoaded, (void*)&input);
269 273
274#if PICA_DUMP_GEOMETRY
270 // NOTE: When dumping geometry, we simply assume that the first input attribute 275 // NOTE: When dumping geometry, we simply assume that the first input attribute
271 // corresponds to the position for now. 276 // corresponds to the position for now.
272 DebugUtils::GeometryDumper::Vertex dumped_vertex = { 277 DebugUtils::GeometryDumper::Vertex dumped_vertex = {
@@ -276,6 +281,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
276 dumping_primitive_assembler.SubmitVertex(dumped_vertex, 281 dumping_primitive_assembler.SubmitVertex(dumped_vertex,
277 std::bind(&DebugUtils::GeometryDumper::AddTriangle, 282 std::bind(&DebugUtils::GeometryDumper::AddTriangle,
278 &geometry_dumper, _1, _2, _3)); 283 &geometry_dumper, _1, _2, _3));
284#endif
279 285
280 // Send to vertex shader 286 // Send to vertex shader
281 VertexShader::OutputVertex output = VertexShader::RunShader(input, attribute_config.GetNumTotalAttributes(), g_state.regs.vs, g_state.vs); 287 VertexShader::OutputVertex output = VertexShader::RunShader(input, attribute_config.GetNumTotalAttributes(), g_state.regs.vs, g_state.vs);
@@ -308,7 +314,9 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
308 VideoCore::g_renderer->hw_rasterizer->DrawTriangles(); 314 VideoCore::g_renderer->hw_rasterizer->DrawTriangles();
309 } 315 }
310 316
317#if PICA_DUMP_GEOMETRY
311 geometry_dumper.Dump(); 318 geometry_dumper.Dump();
319#endif
312 320
313 if (g_debug_context) { 321 if (g_debug_context) {
314 g_debug_context->OnEvent(DebugContext::Event::FinishedPrimitiveBatch, nullptr); 322 g_debug_context->OnEvent(DebugContext::Event::FinishedPrimitiveBatch, nullptr);
@@ -424,7 +432,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
424 VideoCore::g_renderer->hw_rasterizer->NotifyPicaRegisterChanged(id); 432 VideoCore::g_renderer->hw_rasterizer->NotifyPicaRegisterChanged(id);
425 433
426 if (g_debug_context) 434 if (g_debug_context)
427 g_debug_context->OnEvent(DebugContext::Event::CommandProcessed, reinterpret_cast<void*>(&id)); 435 g_debug_context->OnEvent(DebugContext::Event::PicaCommandProcessed, reinterpret_cast<void*>(&id));
428} 436}
429 437
430void ProcessCommandList(const u32* list, u32 size) { 438void ProcessCommandList(const u32* list, u32 size) {
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp
index d24c0f11e..e9a858411 100644
--- a/src/video_core/debug_utils/debug_utils.cpp
+++ b/src/video_core/debug_utils/debug_utils.cpp
@@ -85,15 +85,11 @@ void GeometryDumper::AddTriangle(Vertex& v0, Vertex& v1, Vertex& v2) {
85 vertices.push_back(v1); 85 vertices.push_back(v1);
86 vertices.push_back(v2); 86 vertices.push_back(v2);
87 87
88 int num_vertices = vertices.size(); 88 int num_vertices = (int)vertices.size();
89 faces.push_back({ num_vertices-3, num_vertices-2, num_vertices-1 }); 89 faces.push_back({ num_vertices-3, num_vertices-2, num_vertices-1 });
90} 90}
91 91
92void GeometryDumper::Dump() { 92void GeometryDumper::Dump() {
93 // NOTE: Permanently enabling this just trashes the hard disk for no reason.
94 // Hence, this is currently disabled.
95 return;
96
97 static int index = 0; 93 static int index = 0;
98 std::string filename = std::string("geometry_dump") + std::to_string(++index) + ".obj"; 94 std::string filename = std::string("geometry_dump") + std::to_string(++index) + ".obj";
99 95
@@ -116,10 +112,6 @@ void GeometryDumper::Dump() {
116void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data, u32 swizzle_size, 112void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data, u32 swizzle_size,
117 u32 main_offset, const Regs::VSOutputAttributes* output_attributes) 113 u32 main_offset, const Regs::VSOutputAttributes* output_attributes)
118{ 114{
119 // NOTE: Permanently enabling this just trashes hard disks for no reason.
120 // Hence, this is currently disabled.
121 return;
122
123 struct StuffToWrite { 115 struct StuffToWrite {
124 u8* pointer; 116 u8* pointer;
125 u32 size; 117 u32 size;
@@ -241,8 +233,8 @@ void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data
241 233
242 dvle.main_offset_words = main_offset; 234 dvle.main_offset_words = main_offset;
243 dvle.output_register_table_offset = write_offset - dvlb.dvle_offset; 235 dvle.output_register_table_offset = write_offset - dvlb.dvle_offset;
244 dvle.output_register_table_size = output_info_table.size(); 236 dvle.output_register_table_size = static_cast<uint32_t>(output_info_table.size());
245 QueueForWriting((u8*)output_info_table.data(), output_info_table.size() * sizeof(OutputRegisterInfo)); 237 QueueForWriting((u8*)output_info_table.data(), static_cast<u32>(output_info_table.size() * sizeof(OutputRegisterInfo)));
246 238
247 // TODO: Create a label table for "main" 239 // TODO: Create a label table for "main"
248 240
@@ -497,31 +489,31 @@ const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const Texture
497 // Lookup base value 489 // Lookup base value
498 Math::Vec3<int> ret; 490 Math::Vec3<int> ret;
499 if (differential_mode) { 491 if (differential_mode) {
500 ret.r() = differential.r; 492 ret.r() = static_cast<int>(differential.r);
501 ret.g() = differential.g; 493 ret.g() = static_cast<int>(differential.g);
502 ret.b() = differential.b; 494 ret.b() = static_cast<int>(differential.b);
503 if (x >= 2) { 495 if (x >= 2) {
504 ret.r() += differential.dr; 496 ret.r() += static_cast<int>(differential.dr);
505 ret.g() += differential.dg; 497 ret.g() += static_cast<int>(differential.dg);
506 ret.b() += differential.db; 498 ret.b() += static_cast<int>(differential.db);
507 } 499 }
508 ret.r() = Color::Convert5To8(ret.r()); 500 ret.r() = Color::Convert5To8(ret.r());
509 ret.g() = Color::Convert5To8(ret.g()); 501 ret.g() = Color::Convert5To8(ret.g());
510 ret.b() = Color::Convert5To8(ret.b()); 502 ret.b() = Color::Convert5To8(ret.b());
511 } else { 503 } else {
512 if (x < 2) { 504 if (x < 2) {
513 ret.r() = Color::Convert4To8(separate.r1); 505 ret.r() = Color::Convert4To8(static_cast<u8>(separate.r1));
514 ret.g() = Color::Convert4To8(separate.g1); 506 ret.g() = Color::Convert4To8(static_cast<u8>(separate.g1));
515 ret.b() = Color::Convert4To8(separate.b1); 507 ret.b() = Color::Convert4To8(static_cast<u8>(separate.b1));
516 } else { 508 } else {
517 ret.r() = Color::Convert4To8(separate.r2); 509 ret.r() = Color::Convert4To8(static_cast<u8>(separate.r2));
518 ret.g() = Color::Convert4To8(separate.g2); 510 ret.g() = Color::Convert4To8(static_cast<u8>(separate.g2));
519 ret.b() = Color::Convert4To8(separate.b2); 511 ret.b() = Color::Convert4To8(static_cast<u8>(separate.b2));
520 } 512 }
521 } 513 }
522 514
523 // Add modifier 515 // Add modifier
524 unsigned table_index = (x < 2) ? table_index_1.Value() : table_index_2.Value(); 516 unsigned table_index = static_cast<int>((x < 2) ? table_index_1.Value() : table_index_2.Value());
525 517
526 static const std::array<std::array<u8, 2>, 8> etc1_modifier_table = {{ 518 static const std::array<std::array<u8, 2>, 8> etc1_modifier_table = {{
527 { 2, 8 }, { 5, 17 }, { 9, 29 }, { 13, 42 }, 519 { 2, 8 }, { 5, 17 }, { 9, 29 }, { 13, 42 },
@@ -565,10 +557,6 @@ TextureInfo TextureInfo::FromPicaRegister(const Regs::TextureConfig& config,
565} 557}
566 558
567void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) { 559void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) {
568 // NOTE: Permanently enabling this just trashes hard disks for no reason.
569 // Hence, this is currently disabled.
570 return;
571
572#ifndef HAVE_PNG 560#ifndef HAVE_PNG
573 return; 561 return;
574#else 562#else
diff --git a/src/video_core/debug_utils/debug_utils.h b/src/video_core/debug_utils/debug_utils.h
index 2573292e2..81eea30a9 100644
--- a/src/video_core/debug_utils/debug_utils.h
+++ b/src/video_core/debug_utils/debug_utils.h
@@ -25,11 +25,14 @@ public:
25 enum class Event { 25 enum class Event {
26 FirstEvent = 0, 26 FirstEvent = 0,
27 27
28 CommandLoaded = FirstEvent, 28 PicaCommandLoaded = FirstEvent,
29 CommandProcessed, 29 PicaCommandProcessed,
30 IncomingPrimitiveBatch, 30 IncomingPrimitiveBatch,
31 FinishedPrimitiveBatch, 31 FinishedPrimitiveBatch,
32 VertexLoaded, 32 VertexLoaded,
33 IncomingDisplayTransfer,
34 GSPCommandProcessed,
35 BufferSwapped,
33 36
34 NumEvents 37 NumEvents
35 }; 38 };
@@ -154,6 +157,11 @@ extern std::shared_ptr<DebugContext> g_debug_context; // TODO: Get rid of this g
154 157
155namespace DebugUtils { 158namespace DebugUtils {
156 159
160#define PICA_DUMP_GEOMETRY 0
161#define PICA_DUMP_SHADERS 0
162#define PICA_DUMP_TEXTURES 0
163#define PICA_LOG_TEV 0
164
157// Simple utility class for dumping geometry data to an OBJ file 165// Simple utility class for dumping geometry data to an OBJ file
158class GeometryDumper { 166class GeometryDumper {
159public: 167public:
diff --git a/src/video_core/pica.cpp b/src/video_core/pica.cpp
index 543d9c443..17cb66780 100644
--- a/src/video_core/pica.cpp
+++ b/src/video_core/pica.cpp
@@ -2,7 +2,8 @@
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.h> 5#include <cstring>
6#include <unordered_map>
6 7
7#include "pica.h" 8#include "pica.h"
8 9
@@ -10,6 +11,75 @@ namespace Pica {
10 11
11State g_state; 12State g_state;
12 13
14std::string Regs::GetCommandName(int index) {
15 static std::unordered_map<u32, std::string> map;
16
17 if (map.empty()) {
18 #define ADD_FIELD(name) \
19 map.insert({static_cast<u32>(PICA_REG_INDEX(name)), #name}); \
20 /* TODO: change to Regs::name when VS2015 and other compilers support it */ \
21 for (u32 i = PICA_REG_INDEX(name) + 1; i < PICA_REG_INDEX(name) + sizeof(Regs().name) / 4; ++i) \
22 map.insert({i, #name + std::string("+") + std::to_string(i-PICA_REG_INDEX(name))}); \
23
24 ADD_FIELD(trigger_irq);
25 ADD_FIELD(cull_mode);
26 ADD_FIELD(viewport_size_x);
27 ADD_FIELD(viewport_size_y);
28 ADD_FIELD(viewport_depth_range);
29 ADD_FIELD(viewport_depth_far_plane);
30 ADD_FIELD(viewport_corner);
31 ADD_FIELD(texture0_enable);
32 ADD_FIELD(texture0);
33 ADD_FIELD(texture0_format);
34 ADD_FIELD(texture1);
35 ADD_FIELD(texture1_format);
36 ADD_FIELD(texture2);
37 ADD_FIELD(texture2_format);
38 ADD_FIELD(tev_stage0);
39 ADD_FIELD(tev_stage1);
40 ADD_FIELD(tev_stage2);
41 ADD_FIELD(tev_stage3);
42 ADD_FIELD(tev_combiner_buffer_input);
43 ADD_FIELD(tev_stage4);
44 ADD_FIELD(tev_stage5);
45 ADD_FIELD(tev_combiner_buffer_color);
46 ADD_FIELD(output_merger);
47 ADD_FIELD(framebuffer);
48 ADD_FIELD(vertex_attributes);
49 ADD_FIELD(index_array);
50 ADD_FIELD(num_vertices);
51 ADD_FIELD(trigger_draw);
52 ADD_FIELD(trigger_draw_indexed);
53 ADD_FIELD(vs_default_attributes_setup);
54 ADD_FIELD(command_buffer);
55 ADD_FIELD(triangle_topology);
56 ADD_FIELD(gs.bool_uniforms);
57 ADD_FIELD(gs.int_uniforms);
58 ADD_FIELD(gs.main_offset);
59 ADD_FIELD(gs.input_register_map);
60 ADD_FIELD(gs.uniform_setup);
61 ADD_FIELD(gs.program);
62 ADD_FIELD(gs.swizzle_patterns);
63 ADD_FIELD(vs.bool_uniforms);
64 ADD_FIELD(vs.int_uniforms);
65 ADD_FIELD(vs.main_offset);
66 ADD_FIELD(vs.input_register_map);
67 ADD_FIELD(vs.uniform_setup);
68 ADD_FIELD(vs.program);
69 ADD_FIELD(vs.swizzle_patterns);
70
71#undef ADD_FIELD
72 }
73
74 // Return empty string if no match is found
75 auto it = map.find(index);
76 if (it != map.end()) {
77 return it->second;
78 } else {
79 return std::string();
80 }
81}
82
13void Init() { 83void Init() {
14} 84}
15 85
diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index aec6f0660..34b02b2f8 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -7,7 +7,6 @@
7#include <array> 7#include <array>
8#include <cmath> 8#include <cmath>
9#include <cstddef> 9#include <cstddef>
10#include <map>
11#include <string> 10#include <string>
12 11
13#include "common/assert.h" 12#include "common/assert.h"
@@ -908,69 +907,7 @@ struct Regs {
908 907
909 // Map register indices to names readable by humans 908 // Map register indices to names readable by humans
910 // Used for debugging purposes, so performance is not an issue here 909 // Used for debugging purposes, so performance is not an issue here
911 static std::string GetCommandName(int index) { 910 static std::string GetCommandName(int index);
912 std::map<u32, std::string> map;
913
914 #define ADD_FIELD(name) \
915 do { \
916 map.insert({PICA_REG_INDEX(name), #name}); \
917 /* TODO: change to Regs::name when VS2015 and other compilers support it */ \
918 for (u32 i = PICA_REG_INDEX(name) + 1; i < PICA_REG_INDEX(name) + sizeof(Regs().name) / 4; ++i) \
919 map.insert({i, #name + std::string("+") + std::to_string(i-PICA_REG_INDEX(name))}); \
920 } while(false)
921
922 ADD_FIELD(trigger_irq);
923 ADD_FIELD(cull_mode);
924 ADD_FIELD(viewport_size_x);
925 ADD_FIELD(viewport_size_y);
926 ADD_FIELD(viewport_depth_range);
927 ADD_FIELD(viewport_depth_far_plane);
928 ADD_FIELD(viewport_corner);
929 ADD_FIELD(texture0_enable);
930 ADD_FIELD(texture0);
931 ADD_FIELD(texture0_format);
932 ADD_FIELD(texture1);
933 ADD_FIELD(texture1_format);
934 ADD_FIELD(texture2);
935 ADD_FIELD(texture2_format);
936 ADD_FIELD(tev_stage0);
937 ADD_FIELD(tev_stage1);
938 ADD_FIELD(tev_stage2);
939 ADD_FIELD(tev_stage3);
940 ADD_FIELD(tev_combiner_buffer_input);
941 ADD_FIELD(tev_stage4);
942 ADD_FIELD(tev_stage5);
943 ADD_FIELD(tev_combiner_buffer_color);
944 ADD_FIELD(output_merger);
945 ADD_FIELD(framebuffer);
946 ADD_FIELD(vertex_attributes);
947 ADD_FIELD(index_array);
948 ADD_FIELD(num_vertices);
949 ADD_FIELD(trigger_draw);
950 ADD_FIELD(trigger_draw_indexed);
951 ADD_FIELD(vs_default_attributes_setup);
952 ADD_FIELD(command_buffer);
953 ADD_FIELD(triangle_topology);
954 ADD_FIELD(gs.bool_uniforms);
955 ADD_FIELD(gs.int_uniforms);
956 ADD_FIELD(gs.main_offset);
957 ADD_FIELD(gs.input_register_map);
958 ADD_FIELD(gs.uniform_setup);
959 ADD_FIELD(gs.program);
960 ADD_FIELD(gs.swizzle_patterns);
961 ADD_FIELD(vs.bool_uniforms);
962 ADD_FIELD(vs.int_uniforms);
963 ADD_FIELD(vs.main_offset);
964 ADD_FIELD(vs.input_register_map);
965 ADD_FIELD(vs.uniform_setup);
966 ADD_FIELD(vs.program);
967 ADD_FIELD(vs.swizzle_patterns);
968
969 #undef ADD_FIELD
970
971 // Return empty string if no match is found
972 return map[index];
973 }
974 911
975 static inline size_t NumIds() { 912 static inline size_t NumIds() {
976 return sizeof(Regs) / sizeof(u32); 913 return sizeof(Regs) / sizeof(u32);
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp
index e2b90ad1c..68b7cc05d 100644
--- a/src/video_core/rasterizer.cpp
+++ b/src/video_core/rasterizer.cpp
@@ -462,7 +462,9 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
462 462
463 // TODO: Apply the min and mag filters to the texture 463 // TODO: Apply the min and mag filters to the texture
464 texture_color[i] = DebugUtils::LookupTexture(texture_data, s, t, info); 464 texture_color[i] = DebugUtils::LookupTexture(texture_data, s, t, info);
465#if PICA_DUMP_TEXTURES
465 DebugUtils::DumpTexture(texture.config, texture_data); 466 DebugUtils::DumpTexture(texture.config, texture_data);
467#endif
466 } 468 }
467 } 469 }
468 470
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.cpp b/src/video_core/renderer_opengl/gl_resource_manager.cpp
deleted file mode 100644
index 8f4ae28a4..000000000
--- a/src/video_core/renderer_opengl/gl_resource_manager.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "video_core/renderer_opengl/gl_resource_manager.h"
6#include "video_core/renderer_opengl/gl_shader_util.h"
7
8// Textures
9OGLTexture::OGLTexture() : handle(0) {
10}
11
12OGLTexture::~OGLTexture() {
13 Release();
14}
15
16void OGLTexture::Create() {
17 if (handle != 0) {
18 return;
19 }
20
21 glGenTextures(1, &handle);
22}
23
24void OGLTexture::Release() {
25 glDeleteTextures(1, &handle);
26 handle = 0;
27}
28
29// Shaders
30OGLShader::OGLShader() : handle(0) {
31}
32
33OGLShader::~OGLShader() {
34 Release();
35}
36
37void OGLShader::Create(const char* vert_shader, const char* frag_shader) {
38 if (handle != 0) {
39 return;
40 }
41
42 handle = ShaderUtil::LoadShaders(vert_shader, frag_shader);
43}
44
45void OGLShader::Release() {
46 glDeleteProgram(handle);
47 handle = 0;
48}
49
50// Buffer objects
51OGLBuffer::OGLBuffer() : handle(0) {
52}
53
54OGLBuffer::~OGLBuffer() {
55 Release();
56}
57
58void OGLBuffer::Create() {
59 if (handle != 0) {
60 return;
61 }
62
63 glGenBuffers(1, &handle);
64}
65
66void OGLBuffer::Release() {
67 glDeleteBuffers(1, &handle);
68 handle = 0;
69}
70
71// Vertex array objects
72OGLVertexArray::OGLVertexArray() : handle(0) {
73}
74
75OGLVertexArray::~OGLVertexArray() {
76 Release();
77}
78
79void OGLVertexArray::Create() {
80 if (handle != 0) {
81 return;
82 }
83
84 glGenVertexArrays(1, &handle);
85}
86
87void OGLVertexArray::Release() {
88 glDeleteVertexArrays(1, &handle);
89 handle = 0;
90}
91
92// Framebuffers
93OGLFramebuffer::OGLFramebuffer() : handle(0) {
94}
95
96OGLFramebuffer::~OGLFramebuffer() {
97 Release();
98}
99
100void OGLFramebuffer::Create() {
101 if (handle != 0) {
102 return;
103 }
104
105 glGenFramebuffers(1, &handle);
106}
107
108void OGLFramebuffer::Release() {
109 glDeleteFramebuffers(1, &handle);
110 handle = 0;
111}
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.h b/src/video_core/renderer_opengl/gl_resource_manager.h
index 975720d0a..6f9dc012d 100644
--- a/src/video_core/renderer_opengl/gl_resource_manager.h
+++ b/src/video_core/renderer_opengl/gl_resource_manager.h
@@ -4,76 +4,124 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <utility>
8
7#include "common/common_types.h" 9#include "common/common_types.h"
8 10
9#include "generated/gl_3_2_core.h" 11#include "video_core/renderer_opengl/generated/gl_3_2_core.h"
12#include "video_core/renderer_opengl/gl_shader_util.h"
10 13
11class OGLTexture : public NonCopyable { 14class OGLTexture : private NonCopyable {
12public: 15public:
13 OGLTexture(); 16 OGLTexture() = default;
14 ~OGLTexture(); 17 OGLTexture(OGLTexture&& o) { std::swap(handle, o.handle); }
18 ~OGLTexture() { Release(); }
19 OGLTexture& operator=(OGLTexture&& o) { std::swap(handle, o.handle); return *this; }
15 20
16 /// Creates a new internal OpenGL resource and stores the handle 21 /// Creates a new internal OpenGL resource and stores the handle
17 void Create(); 22 void Create() {
23 if (handle != 0) return;
24 glGenTextures(1, &handle);
25 }
18 26
19 /// Deletes the internal OpenGL resource 27 /// Deletes the internal OpenGL resource
20 void Release(); 28 void Release() {
29 if (handle == 0) return;
30 glDeleteTextures(1, &handle);
31 handle = 0;
32 }
21 33
22 GLuint handle; 34 GLuint handle = 0;
23}; 35};
24 36
25class OGLShader : public NonCopyable { 37class OGLShader : private NonCopyable {
26public: 38public:
27 OGLShader(); 39 OGLShader() = default;
28 ~OGLShader(); 40 OGLShader(OGLShader&& o) { std::swap(handle, o.handle); }
41 ~OGLShader() { Release(); }
42 OGLShader& operator=(OGLShader&& o) { std::swap(handle, o.handle); return *this; }
29 43
30 /// Creates a new internal OpenGL resource and stores the handle 44 /// Creates a new internal OpenGL resource and stores the handle
31 void Create(const char* vert_shader, const char* frag_shader); 45 void Create(const char* vert_shader, const char* frag_shader) {
46 if (handle != 0) return;
47 handle = ShaderUtil::LoadShaders(vert_shader, frag_shader);
48 }
32 49
33 /// Deletes the internal OpenGL resource 50 /// Deletes the internal OpenGL resource
34 void Release(); 51 void Release() {
52 if (handle == 0) return;
53 glDeleteProgram(handle);
54 handle = 0;
55 }
35 56
36 GLuint handle; 57 GLuint handle = 0;
37}; 58};
38 59
39class OGLBuffer : public NonCopyable { 60class OGLBuffer : private NonCopyable {
40public: 61public:
41 OGLBuffer(); 62 OGLBuffer() = default;
42 ~OGLBuffer(); 63 OGLBuffer(OGLBuffer&& o) { std::swap(handle, o.handle); }
64 ~OGLBuffer() { Release(); }
65 OGLBuffer& operator=(OGLBuffer&& o) { std::swap(handle, o.handle); return *this; }
43 66
44 /// Creates a new internal OpenGL resource and stores the handle 67 /// Creates a new internal OpenGL resource and stores the handle
45 void Create(); 68 void Create() {
69 if (handle != 0) return;
70 glGenBuffers(1, &handle);
71 }
46 72
47 /// Deletes the internal OpenGL resource 73 /// Deletes the internal OpenGL resource
48 void Release(); 74 void Release() {
75 if (handle == 0) return;
76 glDeleteBuffers(1, &handle);
77 handle = 0;
78 }
49 79
50 GLuint handle; 80 GLuint handle = 0;
51}; 81};
52 82
53class OGLVertexArray : public NonCopyable { 83class OGLVertexArray : private NonCopyable {
54public: 84public:
55 OGLVertexArray(); 85 OGLVertexArray() = default;
56 ~OGLVertexArray(); 86 OGLVertexArray(OGLVertexArray&& o) { std::swap(handle, o.handle); }
87 ~OGLVertexArray() { Release(); }
88 OGLVertexArray& operator=(OGLVertexArray&& o) { std::swap(handle, o.handle); return *this; }
57 89
58 /// Creates a new internal OpenGL resource and stores the handle 90 /// Creates a new internal OpenGL resource and stores the handle
59 void Create(); 91 void Create() {
92 if (handle != 0) return;
93 glGenVertexArrays(1, &handle);
94 }
60 95
61 /// Deletes the internal OpenGL resource 96 /// Deletes the internal OpenGL resource
62 void Release(); 97 void Release() {
98 if (handle == 0) return;
99 glDeleteVertexArrays(1, &handle);
100 handle = 0;
101 }
63 102
64 GLuint handle; 103 GLuint handle = 0;
65}; 104};
66 105
67class OGLFramebuffer : public NonCopyable { 106class OGLFramebuffer : private NonCopyable {
68public: 107public:
69 OGLFramebuffer(); 108 OGLFramebuffer() = default;
70 ~OGLFramebuffer(); 109 OGLFramebuffer(OGLFramebuffer&& o) { std::swap(handle, o.handle); }
110 ~OGLFramebuffer() { Release(); }
111 OGLFramebuffer& operator=(OGLFramebuffer&& o) { std::swap(handle, o.handle); return *this; }
71 112
72 /// Creates a new internal OpenGL resource and stores the handle 113 /// Creates a new internal OpenGL resource and stores the handle
73 void Create(); 114 void Create() {
115 if (handle != 0) return;
116 glGenFramebuffers(1, &handle);
117 }
74 118
75 /// Deletes the internal OpenGL resource 119 /// Deletes the internal OpenGL resource
76 void Release(); 120 void Release() {
121 if (handle == 0) return;
122 glDeleteFramebuffers(1, &handle);
123 handle = 0;
124 }
77 125
78 GLuint handle; 126 GLuint handle = 0;
79}; 127};
diff --git a/src/video_core/vertex_shader.cpp b/src/video_core/vertex_shader.cpp
index ff114fc3a..5f66f3455 100644
--- a/src/video_core/vertex_shader.cpp
+++ b/src/video_core/vertex_shader.cpp
@@ -2,8 +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 <stack> 5#include <boost/container/static_vector.hpp>
6
7#include <boost/range/algorithm.hpp> 6#include <boost/range/algorithm.hpp>
8 7
9#include <common/file_util.h> 8#include <common/file_util.h>
@@ -27,7 +26,7 @@ namespace Pica {
27namespace VertexShader { 26namespace VertexShader {
28 27
29struct VertexShaderState { 28struct VertexShaderState {
30 const u32* program_counter; 29 u32 program_counter;
31 30
32 const float24* input_register_table[16]; 31 const float24* input_register_table[16];
33 Math::Vec4<float24> output_registers[16]; 32 Math::Vec4<float24> output_registers[16];
@@ -53,7 +52,7 @@ struct VertexShaderState {
53 }; 52 };
54 53
55 // TODO: Is there a maximal size for this? 54 // TODO: Is there a maximal size for this?
56 std::stack<CallStackElement> call_stack; 55 boost::container::static_vector<CallStackElement, 16> call_stack;
57 56
58 struct { 57 struct {
59 u32 max_offset; // maximum program counter ever reached 58 u32 max_offset; // maximum program counter ever reached
@@ -71,15 +70,15 @@ static void ProcessShaderCode(VertexShaderState& state) {
71 70
72 while (true) { 71 while (true) {
73 if (!state.call_stack.empty()) { 72 if (!state.call_stack.empty()) {
74 auto& top = state.call_stack.top(); 73 auto& top = state.call_stack.back();
75 if (state.program_counter - program_code.data() == top.final_address) { 74 if (state.program_counter == top.final_address) {
76 state.address_registers[2] += top.loop_increment; 75 state.address_registers[2] += top.loop_increment;
77 76
78 if (top.repeat_counter-- == 0) { 77 if (top.repeat_counter-- == 0) {
79 state.program_counter = &program_code[top.return_address]; 78 state.program_counter = top.return_address;
80 state.call_stack.pop(); 79 state.call_stack.pop_back();
81 } else { 80 } else {
82 state.program_counter = &program_code[top.loop_address]; 81 state.program_counter = top.loop_address;
83 } 82 }
84 83
85 // TODO: Is "trying again" accurate to hardware? 84 // TODO: Is "trying again" accurate to hardware?
@@ -88,17 +87,16 @@ static void ProcessShaderCode(VertexShaderState& state) {
88 } 87 }
89 88
90 bool exit_loop = false; 89 bool exit_loop = false;
91 const Instruction& instr = *(const Instruction*)state.program_counter; 90 const Instruction instr = { program_code[state.program_counter] };
92 const SwizzlePattern& swizzle = *(SwizzlePattern*)&swizzle_data[instr.common.operand_desc_id]; 91 const SwizzlePattern swizzle = { swizzle_data[instr.common.operand_desc_id] };
93 92
94 static auto call = [&program_code](VertexShaderState& state, u32 offset, u32 num_instructions, 93 static auto call = [](VertexShaderState& state, u32 offset, u32 num_instructions,
95 u32 return_offset, u8 repeat_count, u8 loop_increment) { 94 u32 return_offset, u8 repeat_count, u8 loop_increment) {
96 state.program_counter = &program_code[offset] - 1; // -1 to make sure when incrementing the PC we end up at the correct offset 95 state.program_counter = offset - 1; // -1 to make sure when incrementing the PC we end up at the correct offset
97 state.call_stack.push({ offset + num_instructions, return_offset, repeat_count, loop_increment, offset }); 96 ASSERT(state.call_stack.size() < state.call_stack.capacity());
97 state.call_stack.push_back({ offset + num_instructions, return_offset, repeat_count, loop_increment, offset });
98 }; 98 };
99 u32 binary_offset = state.program_counter - program_code.data(); 99 state.debug.max_offset = std::max<u32>(state.debug.max_offset, 1 + state.program_counter);
100
101 state.debug.max_offset = std::max<u32>(state.debug.max_offset, 1 + binary_offset);
102 100
103 auto LookupSourceRegister = [&](const SourceRegister& source_reg) -> const float24* { 101 auto LookupSourceRegister = [&](const SourceRegister& source_reg) -> const float24* {
104 switch (source_reg.GetRegisterType()) { 102 switch (source_reg.GetRegisterType()) {
@@ -442,13 +440,13 @@ static void ProcessShaderCode(VertexShaderState& state) {
442 440
443 case OpCode::Id::JMPC: 441 case OpCode::Id::JMPC:
444 if (evaluate_condition(state, instr.flow_control.refx, instr.flow_control.refy, instr.flow_control)) { 442 if (evaluate_condition(state, instr.flow_control.refx, instr.flow_control.refy, instr.flow_control)) {
445 state.program_counter = &program_code[instr.flow_control.dest_offset] - 1; 443 state.program_counter = instr.flow_control.dest_offset - 1;
446 } 444 }
447 break; 445 break;
448 446
449 case OpCode::Id::JMPU: 447 case OpCode::Id::JMPU:
450 if (uniforms.b[instr.flow_control.bool_uniform_id]) { 448 if (uniforms.b[instr.flow_control.bool_uniform_id]) {
451 state.program_counter = &program_code[instr.flow_control.dest_offset] - 1; 449 state.program_counter = instr.flow_control.dest_offset - 1;
452 } 450 }
453 break; 451 break;
454 452
@@ -456,7 +454,7 @@ static void ProcessShaderCode(VertexShaderState& state) {
456 call(state, 454 call(state,
457 instr.flow_control.dest_offset, 455 instr.flow_control.dest_offset,
458 instr.flow_control.num_instructions, 456 instr.flow_control.num_instructions,
459 binary_offset + 1, 0, 0); 457 state.program_counter + 1, 0, 0);
460 break; 458 break;
461 459
462 case OpCode::Id::CALLU: 460 case OpCode::Id::CALLU:
@@ -464,7 +462,7 @@ static void ProcessShaderCode(VertexShaderState& state) {
464 call(state, 462 call(state,
465 instr.flow_control.dest_offset, 463 instr.flow_control.dest_offset,
466 instr.flow_control.num_instructions, 464 instr.flow_control.num_instructions,
467 binary_offset + 1, 0, 0); 465 state.program_counter + 1, 0, 0);
468 } 466 }
469 break; 467 break;
470 468
@@ -473,7 +471,7 @@ static void ProcessShaderCode(VertexShaderState& state) {
473 call(state, 471 call(state,
474 instr.flow_control.dest_offset, 472 instr.flow_control.dest_offset,
475 instr.flow_control.num_instructions, 473 instr.flow_control.num_instructions,
476 binary_offset + 1, 0, 0); 474 state.program_counter + 1, 0, 0);
477 } 475 }
478 break; 476 break;
479 477
@@ -483,8 +481,8 @@ static void ProcessShaderCode(VertexShaderState& state) {
483 case OpCode::Id::IFU: 481 case OpCode::Id::IFU:
484 if (uniforms.b[instr.flow_control.bool_uniform_id]) { 482 if (uniforms.b[instr.flow_control.bool_uniform_id]) {
485 call(state, 483 call(state,
486 binary_offset + 1, 484 state.program_counter + 1,
487 instr.flow_control.dest_offset - binary_offset - 1, 485 instr.flow_control.dest_offset - state.program_counter - 1,
488 instr.flow_control.dest_offset + instr.flow_control.num_instructions, 0, 0); 486 instr.flow_control.dest_offset + instr.flow_control.num_instructions, 0, 0);
489 } else { 487 } else {
490 call(state, 488 call(state,
@@ -501,8 +499,8 @@ static void ProcessShaderCode(VertexShaderState& state) {
501 499
502 if (evaluate_condition(state, instr.flow_control.refx, instr.flow_control.refy, instr.flow_control)) { 500 if (evaluate_condition(state, instr.flow_control.refx, instr.flow_control.refy, instr.flow_control)) {
503 call(state, 501 call(state,
504 binary_offset + 1, 502 state.program_counter + 1,
505 instr.flow_control.dest_offset - binary_offset - 1, 503 instr.flow_control.dest_offset - state.program_counter - 1,
506 instr.flow_control.dest_offset + instr.flow_control.num_instructions, 0, 0); 504 instr.flow_control.dest_offset + instr.flow_control.num_instructions, 0, 0);
507 } else { 505 } else {
508 call(state, 506 call(state,
@@ -519,8 +517,8 @@ static void ProcessShaderCode(VertexShaderState& state) {
519 state.address_registers[2] = uniforms.i[instr.flow_control.int_uniform_id].y; 517 state.address_registers[2] = uniforms.i[instr.flow_control.int_uniform_id].y;
520 518
521 call(state, 519 call(state,
522 binary_offset + 1, 520 state.program_counter + 1,
523 instr.flow_control.dest_offset - binary_offset + 1, 521 instr.flow_control.dest_offset - state.program_counter + 1,
524 instr.flow_control.dest_offset + 1, 522 instr.flow_control.dest_offset + 1,
525 uniforms.i[instr.flow_control.int_uniform_id].x, 523 uniforms.i[instr.flow_control.int_uniform_id].x,
526 uniforms.i[instr.flow_control.int_uniform_id].z); 524 uniforms.i[instr.flow_control.int_uniform_id].z);
@@ -551,8 +549,7 @@ OutputVertex RunShader(const InputVertex& input, int num_attributes, const Regs:
551 549
552 VertexShaderState state; 550 VertexShaderState state;
553 551
554 const u32* main = &setup.program_code[config.main_offset]; 552 state.program_counter = config.main_offset;
555 state.program_counter = (u32*)main;
556 state.debug.max_offset = 0; 553 state.debug.max_offset = 0;
557 state.debug.max_opdesc_id = 0; 554 state.debug.max_opdesc_id = 0;
558 555
@@ -582,9 +579,11 @@ OutputVertex RunShader(const InputVertex& input, int num_attributes, const Regs:
582 state.conditional_code[1] = false; 579 state.conditional_code[1] = false;
583 580
584 ProcessShaderCode(state); 581 ProcessShaderCode(state);
582#if PICA_DUMP_SHADERS
585 DebugUtils::DumpShader(setup.program_code.data(), state.debug.max_offset, setup.swizzle_data.data(), 583 DebugUtils::DumpShader(setup.program_code.data(), state.debug.max_offset, setup.swizzle_data.data(),
586 state.debug.max_opdesc_id, config.main_offset, 584 state.debug.max_opdesc_id, config.main_offset,
587 g_state.regs.vs_output_attributes); // TODO: Don't hardcode VS here 585 g_state.regs.vs_output_attributes); // TODO: Don't hardcode VS here
586#endif
588 587
589 // Setup output data 588 // Setup output data
590 OutputVertex ret; 589 OutputVertex ret;