diff options
Diffstat (limited to 'src/video_core')
-rw-r--r-- | src/video_core/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/video_core/command_processor.cpp | 16 | ||||
-rw-r--r-- | src/video_core/debug_utils/debug_utils.cpp | 44 | ||||
-rw-r--r-- | src/video_core/debug_utils/debug_utils.h | 12 | ||||
-rw-r--r-- | src/video_core/pica.cpp | 72 | ||||
-rw-r--r-- | src/video_core/pica.h | 65 | ||||
-rw-r--r-- | src/video_core/rasterizer.cpp | 2 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_resource_manager.cpp | 111 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_resource_manager.h | 110 | ||||
-rw-r--r-- | src/video_core/vertex_shader.cpp | 59 |
10 files changed, 220 insertions, 272 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 5c7f4ae1..16210830 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -2,7 +2,6 @@ set(SRCS renderer_opengl/generated/gl_3_2_core.c renderer_opengl/gl_rasterizer.cpp renderer_opengl/gl_rasterizer_cache.cpp - renderer_opengl/gl_resource_manager.cpp renderer_opengl/gl_shader_util.cpp renderer_opengl/gl_state.cpp renderer_opengl/renderer_opengl.cpp diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index bbe7e63d..36c3b994 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) { regs[id] = (old_value & ~mask) | (value & mask); if (g_debug_context) - g_debug_context->OnEvent(DebugContext::Event::CommandLoaded, reinterpret_cast<void*>(&id)); + g_debug_context->OnEvent(DebugContext::Event::PicaCommandLoaded, reinterpret_cast<void*>(&id)); DebugUtils::OnPicaRegWrite(id, regs[id]); @@ -103,7 +103,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[0], 0x23c): case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[1], 0x23d): { - unsigned index = id - PICA_REG_INDEX(command_buffer.trigger[0]); + unsigned index = static_cast<unsigned>(id - PICA_REG_INDEX(command_buffer.trigger[0])); u32* head_ptr = (u32*)Memory::GetPhysicalPointer(regs.command_buffer.GetPhysicalAddress(index)); g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = head_ptr; 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) { { Common::Profiling::ScopeTimer scope_timer(category_drawing); +#if PICA_LOG_TEV DebugUtils::DumpTevStageConfig(regs.GetTevStages()); +#endif if (g_debug_context) g_debug_context->OnEvent(DebugContext::Event::IncomingPrimitiveBatch, nullptr); @@ -159,9 +161,11 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { const u16* index_address_16 = (u16*)index_address_8; bool index_u16 = index_info.format != 0; +#if PICA_DUMP_GEOMETRY DebugUtils::GeometryDumper geometry_dumper; - PrimitiveAssembler<VertexShader::OutputVertex> primitive_assembler(regs.triangle_topology.Value()); PrimitiveAssembler<DebugUtils::GeometryDumper::Vertex> dumping_primitive_assembler(regs.triangle_topology.Value()); +#endif + PrimitiveAssembler<VertexShader::OutputVertex> primitive_assembler(regs.triangle_topology.Value()); if (g_debug_context) { for (int i = 0; i < 3; ++i) { @@ -267,6 +271,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { if (g_debug_context) g_debug_context->OnEvent(DebugContext::Event::VertexLoaded, (void*)&input); +#if PICA_DUMP_GEOMETRY // NOTE: When dumping geometry, we simply assume that the first input attribute // corresponds to the position for now. DebugUtils::GeometryDumper::Vertex dumped_vertex = { @@ -276,6 +281,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { dumping_primitive_assembler.SubmitVertex(dumped_vertex, std::bind(&DebugUtils::GeometryDumper::AddTriangle, &geometry_dumper, _1, _2, _3)); +#endif // Send to vertex shader 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) { VideoCore::g_renderer->hw_rasterizer->DrawTriangles(); } +#if PICA_DUMP_GEOMETRY geometry_dumper.Dump(); +#endif if (g_debug_context) { g_debug_context->OnEvent(DebugContext::Event::FinishedPrimitiveBatch, nullptr); @@ -424,7 +432,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { VideoCore::g_renderer->hw_rasterizer->NotifyPicaRegisterChanged(id); if (g_debug_context) - g_debug_context->OnEvent(DebugContext::Event::CommandProcessed, reinterpret_cast<void*>(&id)); + g_debug_context->OnEvent(DebugContext::Event::PicaCommandProcessed, reinterpret_cast<void*>(&id)); } void 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 d24c0f11..e9a85841 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) { vertices.push_back(v1); vertices.push_back(v2); - int num_vertices = vertices.size(); + int num_vertices = (int)vertices.size(); faces.push_back({ num_vertices-3, num_vertices-2, num_vertices-1 }); } void GeometryDumper::Dump() { - // NOTE: Permanently enabling this just trashes the hard disk for no reason. - // Hence, this is currently disabled. - return; - static int index = 0; std::string filename = std::string("geometry_dump") + std::to_string(++index) + ".obj"; @@ -116,10 +112,6 @@ void GeometryDumper::Dump() { void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data, u32 swizzle_size, u32 main_offset, const Regs::VSOutputAttributes* output_attributes) { - // NOTE: Permanently enabling this just trashes hard disks for no reason. - // Hence, this is currently disabled. - return; - struct StuffToWrite { u8* pointer; u32 size; @@ -241,8 +233,8 @@ void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data dvle.main_offset_words = main_offset; dvle.output_register_table_offset = write_offset - dvlb.dvle_offset; - dvle.output_register_table_size = output_info_table.size(); - QueueForWriting((u8*)output_info_table.data(), output_info_table.size() * sizeof(OutputRegisterInfo)); + dvle.output_register_table_size = static_cast<uint32_t>(output_info_table.size()); + QueueForWriting((u8*)output_info_table.data(), static_cast<u32>(output_info_table.size() * sizeof(OutputRegisterInfo))); // TODO: Create a label table for "main" @@ -497,31 +489,31 @@ const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const Texture // Lookup base value Math::Vec3<int> ret; if (differential_mode) { - ret.r() = differential.r; - ret.g() = differential.g; - ret.b() = differential.b; + ret.r() = static_cast<int>(differential.r); + ret.g() = static_cast<int>(differential.g); + ret.b() = static_cast<int>(differential.b); if (x >= 2) { - ret.r() += differential.dr; - ret.g() += differential.dg; - ret.b() += differential.db; + ret.r() += static_cast<int>(differential.dr); + ret.g() += static_cast<int>(differential.dg); + ret.b() += static_cast<int>(differential.db); } ret.r() = Color::Convert5To8(ret.r()); ret.g() = Color::Convert5To8(ret.g()); ret.b() = Color::Convert5To8(ret.b()); } else { if (x < 2) { - ret.r() = Color::Convert4To8(separate.r1); - ret.g() = Color::Convert4To8(separate.g1); - ret.b() = Color::Convert4To8(separate.b1); + ret.r() = Color::Convert4To8(static_cast<u8>(separate.r1)); + ret.g() = Color::Convert4To8(static_cast<u8>(separate.g1)); + ret.b() = Color::Convert4To8(static_cast<u8>(separate.b1)); } else { - ret.r() = Color::Convert4To8(separate.r2); - ret.g() = Color::Convert4To8(separate.g2); - ret.b() = Color::Convert4To8(separate.b2); + ret.r() = Color::Convert4To8(static_cast<u8>(separate.r2)); + ret.g() = Color::Convert4To8(static_cast<u8>(separate.g2)); + ret.b() = Color::Convert4To8(static_cast<u8>(separate.b2)); } } // Add modifier - unsigned table_index = (x < 2) ? table_index_1.Value() : table_index_2.Value(); + unsigned table_index = static_cast<int>((x < 2) ? table_index_1.Value() : table_index_2.Value()); static const std::array<std::array<u8, 2>, 8> etc1_modifier_table = {{ { 2, 8 }, { 5, 17 }, { 9, 29 }, { 13, 42 }, @@ -565,10 +557,6 @@ TextureInfo TextureInfo::FromPicaRegister(const Regs::TextureConfig& config, } void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) { - // NOTE: Permanently enabling this just trashes hard disks for no reason. - // Hence, this is currently disabled. - return; - #ifndef HAVE_PNG return; #else diff --git a/src/video_core/debug_utils/debug_utils.h b/src/video_core/debug_utils/debug_utils.h index 2573292e..81eea30a 100644 --- a/src/video_core/debug_utils/debug_utils.h +++ b/src/video_core/debug_utils/debug_utils.h @@ -25,11 +25,14 @@ public: enum class Event { FirstEvent = 0, - CommandLoaded = FirstEvent, - CommandProcessed, + PicaCommandLoaded = FirstEvent, + PicaCommandProcessed, IncomingPrimitiveBatch, FinishedPrimitiveBatch, VertexLoaded, + IncomingDisplayTransfer, + GSPCommandProcessed, + BufferSwapped, NumEvents }; @@ -154,6 +157,11 @@ extern std::shared_ptr<DebugContext> g_debug_context; // TODO: Get rid of this g namespace DebugUtils { +#define PICA_DUMP_GEOMETRY 0 +#define PICA_DUMP_SHADERS 0 +#define PICA_DUMP_TEXTURES 0 +#define PICA_LOG_TEV 0 + // Simple utility class for dumping geometry data to an OBJ file class GeometryDumper { public: diff --git a/src/video_core/pica.cpp b/src/video_core/pica.cpp index 543d9c44..17cb6678 100644 --- a/src/video_core/pica.cpp +++ b/src/video_core/pica.cpp @@ -2,7 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include <string.h> +#include <cstring> +#include <unordered_map> #include "pica.h" @@ -10,6 +11,75 @@ namespace Pica { State g_state; +std::string Regs::GetCommandName(int index) { + static std::unordered_map<u32, std::string> map; + + if (map.empty()) { + #define ADD_FIELD(name) \ + map.insert({static_cast<u32>(PICA_REG_INDEX(name)), #name}); \ + /* TODO: change to Regs::name when VS2015 and other compilers support it */ \ + for (u32 i = PICA_REG_INDEX(name) + 1; i < PICA_REG_INDEX(name) + sizeof(Regs().name) / 4; ++i) \ + map.insert({i, #name + std::string("+") + std::to_string(i-PICA_REG_INDEX(name))}); \ + + ADD_FIELD(trigger_irq); + ADD_FIELD(cull_mode); + ADD_FIELD(viewport_size_x); + ADD_FIELD(viewport_size_y); + ADD_FIELD(viewport_depth_range); + ADD_FIELD(viewport_depth_far_plane); + ADD_FIELD(viewport_corner); + ADD_FIELD(texture0_enable); + ADD_FIELD(texture0); + ADD_FIELD(texture0_format); + ADD_FIELD(texture1); + ADD_FIELD(texture1_format); + ADD_FIELD(texture2); + ADD_FIELD(texture2_format); + ADD_FIELD(tev_stage0); + ADD_FIELD(tev_stage1); + ADD_FIELD(tev_stage2); + ADD_FIELD(tev_stage3); + ADD_FIELD(tev_combiner_buffer_input); + ADD_FIELD(tev_stage4); + ADD_FIELD(tev_stage5); + ADD_FIELD(tev_combiner_buffer_color); + ADD_FIELD(output_merger); + ADD_FIELD(framebuffer); + ADD_FIELD(vertex_attributes); + ADD_FIELD(index_array); + ADD_FIELD(num_vertices); + ADD_FIELD(trigger_draw); + ADD_FIELD(trigger_draw_indexed); + ADD_FIELD(vs_default_attributes_setup); + ADD_FIELD(command_buffer); + ADD_FIELD(triangle_topology); + ADD_FIELD(gs.bool_uniforms); + ADD_FIELD(gs.int_uniforms); + ADD_FIELD(gs.main_offset); + ADD_FIELD(gs.input_register_map); + ADD_FIELD(gs.uniform_setup); + ADD_FIELD(gs.program); + ADD_FIELD(gs.swizzle_patterns); + ADD_FIELD(vs.bool_uniforms); + ADD_FIELD(vs.int_uniforms); + ADD_FIELD(vs.main_offset); + ADD_FIELD(vs.input_register_map); + ADD_FIELD(vs.uniform_setup); + ADD_FIELD(vs.program); + ADD_FIELD(vs.swizzle_patterns); + +#undef ADD_FIELD + } + + // Return empty string if no match is found + auto it = map.find(index); + if (it != map.end()) { + return it->second; + } else { + return std::string(); + } +} + void Init() { } diff --git a/src/video_core/pica.h b/src/video_core/pica.h index aec6f066..34b02b2f 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h @@ -7,7 +7,6 @@ #include <array> #include <cmath> #include <cstddef> -#include <map> #include <string> #include "common/assert.h" @@ -908,69 +907,7 @@ struct Regs { // Map register indices to names readable by humans // Used for debugging purposes, so performance is not an issue here - static std::string GetCommandName(int index) { - std::map<u32, std::string> map; - - #define ADD_FIELD(name) \ - do { \ - map.insert({PICA_REG_INDEX(name), #name}); \ - /* TODO: change to Regs::name when VS2015 and other compilers support it */ \ - for (u32 i = PICA_REG_INDEX(name) + 1; i < PICA_REG_INDEX(name) + sizeof(Regs().name) / 4; ++i) \ - map.insert({i, #name + std::string("+") + std::to_string(i-PICA_REG_INDEX(name))}); \ - } while(false) - - ADD_FIELD(trigger_irq); - ADD_FIELD(cull_mode); - ADD_FIELD(viewport_size_x); - ADD_FIELD(viewport_size_y); - ADD_FIELD(viewport_depth_range); - ADD_FIELD(viewport_depth_far_plane); - ADD_FIELD(viewport_corner); - ADD_FIELD(texture0_enable); - ADD_FIELD(texture0); - ADD_FIELD(texture0_format); - ADD_FIELD(texture1); - ADD_FIELD(texture1_format); - ADD_FIELD(texture2); - ADD_FIELD(texture2_format); - ADD_FIELD(tev_stage0); - ADD_FIELD(tev_stage1); - ADD_FIELD(tev_stage2); - ADD_FIELD(tev_stage3); - ADD_FIELD(tev_combiner_buffer_input); - ADD_FIELD(tev_stage4); - ADD_FIELD(tev_stage5); - ADD_FIELD(tev_combiner_buffer_color); - ADD_FIELD(output_merger); - ADD_FIELD(framebuffer); - ADD_FIELD(vertex_attributes); - ADD_FIELD(index_array); - ADD_FIELD(num_vertices); - ADD_FIELD(trigger_draw); - ADD_FIELD(trigger_draw_indexed); - ADD_FIELD(vs_default_attributes_setup); - ADD_FIELD(command_buffer); - ADD_FIELD(triangle_topology); - ADD_FIELD(gs.bool_uniforms); - ADD_FIELD(gs.int_uniforms); - ADD_FIELD(gs.main_offset); - ADD_FIELD(gs.input_register_map); - ADD_FIELD(gs.uniform_setup); - ADD_FIELD(gs.program); - ADD_FIELD(gs.swizzle_patterns); - ADD_FIELD(vs.bool_uniforms); - ADD_FIELD(vs.int_uniforms); - ADD_FIELD(vs.main_offset); - ADD_FIELD(vs.input_register_map); - ADD_FIELD(vs.uniform_setup); - ADD_FIELD(vs.program); - ADD_FIELD(vs.swizzle_patterns); - - #undef ADD_FIELD - - // Return empty string if no match is found - return map[index]; - } + static std::string GetCommandName(int index); static inline size_t NumIds() { return sizeof(Regs) / sizeof(u32); diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index e2b90ad1..68b7cc05 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp @@ -462,7 +462,9 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, // TODO: Apply the min and mag filters to the texture texture_color[i] = DebugUtils::LookupTexture(texture_data, s, t, info); +#if PICA_DUMP_TEXTURES DebugUtils::DumpTexture(texture.config, texture_data); +#endif } } 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 8f4ae28a..00000000 --- a/src/video_core/renderer_opengl/gl_resource_manager.cpp +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "video_core/renderer_opengl/gl_resource_manager.h" -#include "video_core/renderer_opengl/gl_shader_util.h" - -// Textures -OGLTexture::OGLTexture() : handle(0) { -} - -OGLTexture::~OGLTexture() { - Release(); -} - -void OGLTexture::Create() { - if (handle != 0) { - return; - } - - glGenTextures(1, &handle); -} - -void OGLTexture::Release() { - glDeleteTextures(1, &handle); - handle = 0; -} - -// Shaders -OGLShader::OGLShader() : handle(0) { -} - -OGLShader::~OGLShader() { - Release(); -} - -void OGLShader::Create(const char* vert_shader, const char* frag_shader) { - if (handle != 0) { - return; - } - - handle = ShaderUtil::LoadShaders(vert_shader, frag_shader); -} - -void OGLShader::Release() { - glDeleteProgram(handle); - handle = 0; -} - -// Buffer objects -OGLBuffer::OGLBuffer() : handle(0) { -} - -OGLBuffer::~OGLBuffer() { - Release(); -} - -void OGLBuffer::Create() { - if (handle != 0) { - return; - } - - glGenBuffers(1, &handle); -} - -void OGLBuffer::Release() { - glDeleteBuffers(1, &handle); - handle = 0; -} - -// Vertex array objects -OGLVertexArray::OGLVertexArray() : handle(0) { -} - -OGLVertexArray::~OGLVertexArray() { - Release(); -} - -void OGLVertexArray::Create() { - if (handle != 0) { - return; - } - - glGenVertexArrays(1, &handle); -} - -void OGLVertexArray::Release() { - glDeleteVertexArrays(1, &handle); - handle = 0; -} - -// Framebuffers -OGLFramebuffer::OGLFramebuffer() : handle(0) { -} - -OGLFramebuffer::~OGLFramebuffer() { - Release(); -} - -void OGLFramebuffer::Create() { - if (handle != 0) { - return; - } - - glGenFramebuffers(1, &handle); -} - -void OGLFramebuffer::Release() { - glDeleteFramebuffers(1, &handle); - handle = 0; -} diff --git a/src/video_core/renderer_opengl/gl_resource_manager.h b/src/video_core/renderer_opengl/gl_resource_manager.h index 975720d0..6f9dc012 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 @@ #pragma once +#include <utility> + #include "common/common_types.h" -#include "generated/gl_3_2_core.h" +#include "video_core/renderer_opengl/generated/gl_3_2_core.h" +#include "video_core/renderer_opengl/gl_shader_util.h" -class OGLTexture : public NonCopyable { +class OGLTexture : private NonCopyable { public: - OGLTexture(); - ~OGLTexture(); + OGLTexture() = default; + OGLTexture(OGLTexture&& o) { std::swap(handle, o.handle); } + ~OGLTexture() { Release(); } + OGLTexture& operator=(OGLTexture&& o) { std::swap(handle, o.handle); return *this; } /// Creates a new internal OpenGL resource and stores the handle - void Create(); + void Create() { + if (handle != 0) return; + glGenTextures(1, &handle); + } /// Deletes the internal OpenGL resource - void Release(); + void Release() { + if (handle == 0) return; + glDeleteTextures(1, &handle); + handle = 0; + } - GLuint handle; + GLuint handle = 0; }; -class OGLShader : public NonCopyable { +class OGLShader : private NonCopyable { public: - OGLShader(); - ~OGLShader(); + OGLShader() = default; + OGLShader(OGLShader&& o) { std::swap(handle, o.handle); } + ~OGLShader() { Release(); } + OGLShader& operator=(OGLShader&& o) { std::swap(handle, o.handle); return *this; } /// Creates a new internal OpenGL resource and stores the handle - void Create(const char* vert_shader, const char* frag_shader); + void Create(const char* vert_shader, const char* frag_shader) { + if (handle != 0) return; + handle = ShaderUtil::LoadShaders(vert_shader, frag_shader); + } /// Deletes the internal OpenGL resource - void Release(); + void Release() { + if (handle == 0) return; + glDeleteProgram(handle); + handle = 0; + } - GLuint handle; + GLuint handle = 0; }; -class OGLBuffer : public NonCopyable { +class OGLBuffer : private NonCopyable { public: - OGLBuffer(); - ~OGLBuffer(); + OGLBuffer() = default; + OGLBuffer(OGLBuffer&& o) { std::swap(handle, o.handle); } + ~OGLBuffer() { Release(); } + OGLBuffer& operator=(OGLBuffer&& o) { std::swap(handle, o.handle); return *this; } /// Creates a new internal OpenGL resource and stores the handle - void Create(); + void Create() { + if (handle != 0) return; + glGenBuffers(1, &handle); + } /// Deletes the internal OpenGL resource - void Release(); + void Release() { + if (handle == 0) return; + glDeleteBuffers(1, &handle); + handle = 0; + } - GLuint handle; + GLuint handle = 0; }; -class OGLVertexArray : public NonCopyable { +class OGLVertexArray : private NonCopyable { public: - OGLVertexArray(); - ~OGLVertexArray(); + OGLVertexArray() = default; + OGLVertexArray(OGLVertexArray&& o) { std::swap(handle, o.handle); } + ~OGLVertexArray() { Release(); } + OGLVertexArray& operator=(OGLVertexArray&& o) { std::swap(handle, o.handle); return *this; } /// Creates a new internal OpenGL resource and stores the handle - void Create(); + void Create() { + if (handle != 0) return; + glGenVertexArrays(1, &handle); + } /// Deletes the internal OpenGL resource - void Release(); + void Release() { + if (handle == 0) return; + glDeleteVertexArrays(1, &handle); + handle = 0; + } - GLuint handle; + GLuint handle = 0; }; -class OGLFramebuffer : public NonCopyable { +class OGLFramebuffer : private NonCopyable { public: - OGLFramebuffer(); - ~OGLFramebuffer(); + OGLFramebuffer() = default; + OGLFramebuffer(OGLFramebuffer&& o) { std::swap(handle, o.handle); } + ~OGLFramebuffer() { Release(); } + OGLFramebuffer& operator=(OGLFramebuffer&& o) { std::swap(handle, o.handle); return *this; } /// Creates a new internal OpenGL resource and stores the handle - void Create(); + void Create() { + if (handle != 0) return; + glGenFramebuffers(1, &handle); + } /// Deletes the internal OpenGL resource - void Release(); + void Release() { + if (handle == 0) return; + glDeleteFramebuffers(1, &handle); + handle = 0; + } - GLuint handle; + GLuint handle = 0; }; diff --git a/src/video_core/vertex_shader.cpp b/src/video_core/vertex_shader.cpp index ff114fc3..5f66f345 100644 --- a/src/video_core/vertex_shader.cpp +++ b/src/video_core/vertex_shader.cpp @@ -2,8 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include <stack> - +#include <boost/container/static_vector.hpp> #include <boost/range/algorithm.hpp> #include <common/file_util.h> @@ -27,7 +26,7 @@ namespace Pica { namespace VertexShader { struct VertexShaderState { - const u32* program_counter; + u32 program_counter; const float24* input_register_table[16]; Math::Vec4<float24> output_registers[16]; @@ -53,7 +52,7 @@ struct VertexShaderState { }; // TODO: Is there a maximal size for this? - std::stack<CallStackElement> call_stack; + boost::container::static_vector<CallStackElement, 16> call_stack; struct { u32 max_offset; // maximum program counter ever reached @@ -71,15 +70,15 @@ static void ProcessShaderCode(VertexShaderState& state) { while (true) { if (!state.call_stack.empty()) { - auto& top = state.call_stack.top(); - if (state.program_counter - program_code.data() == top.final_address) { + auto& top = state.call_stack.back(); + if (state.program_counter == top.final_address) { state.address_registers[2] += top.loop_increment; if (top.repeat_counter-- == 0) { - state.program_counter = &program_code[top.return_address]; - state.call_stack.pop(); + state.program_counter = top.return_address; + state.call_stack.pop_back(); } else { - state.program_counter = &program_code[top.loop_address]; + state.program_counter = top.loop_address; } // TODO: Is "trying again" accurate to hardware? @@ -88,17 +87,16 @@ static void ProcessShaderCode(VertexShaderState& state) { } bool exit_loop = false; - const Instruction& instr = *(const Instruction*)state.program_counter; - const SwizzlePattern& swizzle = *(SwizzlePattern*)&swizzle_data[instr.common.operand_desc_id]; + const Instruction instr = { program_code[state.program_counter] }; + const SwizzlePattern swizzle = { swizzle_data[instr.common.operand_desc_id] }; - static auto call = [&program_code](VertexShaderState& state, u32 offset, u32 num_instructions, + static auto call = [](VertexShaderState& state, u32 offset, u32 num_instructions, u32 return_offset, u8 repeat_count, u8 loop_increment) { - state.program_counter = &program_code[offset] - 1; // -1 to make sure when incrementing the PC we end up at the correct offset - state.call_stack.push({ offset + num_instructions, return_offset, repeat_count, loop_increment, offset }); + state.program_counter = offset - 1; // -1 to make sure when incrementing the PC we end up at the correct offset + ASSERT(state.call_stack.size() < state.call_stack.capacity()); + state.call_stack.push_back({ offset + num_instructions, return_offset, repeat_count, loop_increment, offset }); }; - u32 binary_offset = state.program_counter - program_code.data(); - - state.debug.max_offset = std::max<u32>(state.debug.max_offset, 1 + binary_offset); + state.debug.max_offset = std::max<u32>(state.debug.max_offset, 1 + state.program_counter); auto LookupSourceRegister = [&](const SourceRegister& source_reg) -> const float24* { switch (source_reg.GetRegisterType()) { @@ -442,13 +440,13 @@ static void ProcessShaderCode(VertexShaderState& state) { case OpCode::Id::JMPC: if (evaluate_condition(state, instr.flow_control.refx, instr.flow_control.refy, instr.flow_control)) { - state.program_counter = &program_code[instr.flow_control.dest_offset] - 1; + state.program_counter = instr.flow_control.dest_offset - 1; } break; case OpCode::Id::JMPU: if (uniforms.b[instr.flow_control.bool_uniform_id]) { - state.program_counter = &program_code[instr.flow_control.dest_offset] - 1; + state.program_counter = instr.flow_control.dest_offset - 1; } break; @@ -456,7 +454,7 @@ static void ProcessShaderCode(VertexShaderState& state) { call(state, instr.flow_control.dest_offset, instr.flow_control.num_instructions, - binary_offset + 1, 0, 0); + state.program_counter + 1, 0, 0); break; case OpCode::Id::CALLU: @@ -464,7 +462,7 @@ static void ProcessShaderCode(VertexShaderState& state) { call(state, instr.flow_control.dest_offset, instr.flow_control.num_instructions, - binary_offset + 1, 0, 0); + state.program_counter + 1, 0, 0); } break; @@ -473,7 +471,7 @@ static void ProcessShaderCode(VertexShaderState& state) { call(state, instr.flow_control.dest_offset, instr.flow_control.num_instructions, - binary_offset + 1, 0, 0); + state.program_counter + 1, 0, 0); } break; @@ -483,8 +481,8 @@ static void ProcessShaderCode(VertexShaderState& state) { case OpCode::Id::IFU: if (uniforms.b[instr.flow_control.bool_uniform_id]) { call(state, - binary_offset + 1, - instr.flow_control.dest_offset - binary_offset - 1, + state.program_counter + 1, + instr.flow_control.dest_offset - state.program_counter - 1, instr.flow_control.dest_offset + instr.flow_control.num_instructions, 0, 0); } else { call(state, @@ -501,8 +499,8 @@ static void ProcessShaderCode(VertexShaderState& state) { if (evaluate_condition(state, instr.flow_control.refx, instr.flow_control.refy, instr.flow_control)) { call(state, - binary_offset + 1, - instr.flow_control.dest_offset - binary_offset - 1, + state.program_counter + 1, + instr.flow_control.dest_offset - state.program_counter - 1, instr.flow_control.dest_offset + instr.flow_control.num_instructions, 0, 0); } else { call(state, @@ -519,8 +517,8 @@ static void ProcessShaderCode(VertexShaderState& state) { state.address_registers[2] = uniforms.i[instr.flow_control.int_uniform_id].y; call(state, - binary_offset + 1, - instr.flow_control.dest_offset - binary_offset + 1, + state.program_counter + 1, + instr.flow_control.dest_offset - state.program_counter + 1, instr.flow_control.dest_offset + 1, uniforms.i[instr.flow_control.int_uniform_id].x, uniforms.i[instr.flow_control.int_uniform_id].z); @@ -551,8 +549,7 @@ OutputVertex RunShader(const InputVertex& input, int num_attributes, const Regs: VertexShaderState state; - const u32* main = &setup.program_code[config.main_offset]; - state.program_counter = (u32*)main; + state.program_counter = config.main_offset; state.debug.max_offset = 0; state.debug.max_opdesc_id = 0; @@ -582,9 +579,11 @@ OutputVertex RunShader(const InputVertex& input, int num_attributes, const Regs: state.conditional_code[1] = false; ProcessShaderCode(state); +#if PICA_DUMP_SHADERS DebugUtils::DumpShader(setup.program_code.data(), state.debug.max_offset, setup.swizzle_data.data(), state.debug.max_opdesc_id, config.main_offset, g_state.regs.vs_output_attributes); // TODO: Don't hardcode VS here +#endif // Setup output data OutputVertex ret; |