diff --git a/Utilities/Log.cpp b/Utilities/Log.cpp index f4652da86f..8303baec35 100644 --- a/Utilities/Log.cpp +++ b/Utilities/Log.cpp @@ -57,7 +57,7 @@ LogChannel::LogChannel() : LogChannel("unknown") LogChannel::LogChannel(const std::string& name) : name(name) , mEnabled(true) - , mLogLevel(Warning) + , mLogLevel(LogSeverityWarning) {} void LogChannel::log(const LogMessage &msg) @@ -186,16 +186,16 @@ void LogManager::log(LogMessage msg) std::string prefix; switch (msg.mServerity) { - case Success: + case LogSeveritySuccess: prefix = "S "; break; - case Notice: + case LogSeverityNotice: prefix = "! "; break; - case Warning: + case LogSeverityWarning: prefix = "W "; break; - case Error: + case LogSeverityError: prefix = "E "; break; } @@ -265,12 +265,12 @@ void log_message(Log::LogType type, Log::LogSeverity sev, std::string text) else { rMessageBox(text, - sev == Notice ? "Notice" : - sev == Warning ? "Warning" : - sev == Success ? "Success" : - sev == Error ? "Error" : "Unknown", - sev == Notice ? rICON_INFORMATION : - sev == Warning ? rICON_EXCLAMATION : - sev == Error ? rICON_ERROR : rICON_INFORMATION); + sev == LogSeverityNotice ? "Notice" : + sev == LogSeverityWarning ? "Warning" : + sev == LogSeveritySuccess ? "Success" : + sev == LogSeverityError ? "Error" : "Unknown", + sev == LogSeverityNotice ? rICON_INFORMATION : + sev == LogSeverityWarning ? rICON_EXCLAMATION : + sev == LogSeverityError ? rICON_ERROR : rICON_INFORMATION); } } diff --git a/Utilities/Log.h b/Utilities/Log.h index 2fbbee34de..12c0c7cb21 100644 --- a/Utilities/Log.h +++ b/Utilities/Log.h @@ -5,10 +5,10 @@ //first parameter is of type Log::LogType and text is of type std::string -#define LOG_SUCCESS(logType, text, ...) log_message(logType, Log::Success, text, ##__VA_ARGS__) -#define LOG_NOTICE(logType, text, ...) log_message(logType, Log::Notice, text, ##__VA_ARGS__) -#define LOG_WARNING(logType, text, ...) log_message(logType, Log::Warning, text, ##__VA_ARGS__) -#define LOG_ERROR(logType, text, ...) log_message(logType, Log::Error, text, ##__VA_ARGS__) +#define LOG_SUCCESS(logType, text, ...) log_message(logType, Log::LogSeveritySuccess, text, ##__VA_ARGS__) +#define LOG_NOTICE(logType, text, ...) log_message(logType, Log::LogSeverityNotice, text, ##__VA_ARGS__) +#define LOG_WARNING(logType, text, ...) log_message(logType, Log::LogSeverityWarning, text, ##__VA_ARGS__) +#define LOG_ERROR(logType, text, ...) log_message(logType, Log::LogSeverityError, text, ##__VA_ARGS__) namespace Log { @@ -50,10 +50,10 @@ namespace Log enum LogSeverity : u32 { - Notice = 0, - Warning, - Success, - Error, + LogSeverityNotice = 0, + LogSeverityWarning, + LogSeveritySuccess, + LogSeverityError, }; struct LogMessage diff --git a/rpcs3/Emu/RSX/Common/ProgramStateCache.h b/rpcs3/Emu/RSX/Common/ProgramStateCache.h new file mode 100644 index 0000000000..6a732e7bd7 --- /dev/null +++ b/rpcs3/Emu/RSX/Common/ProgramStateCache.h @@ -0,0 +1,337 @@ +#pragma once + +#include "Emu/RSX/RSXFragmentProgram.h" +#include "Emu/RSX/RSXVertexProgram.h" +#include "Utilities/Log.h" + + +enum class SHADER_TYPE +{ + SHADER_TYPE_VERTEX, + SHADER_TYPE_FRAGMENT +}; + +namespace ProgramHashUtil +{ + // Based on + // https://github.com/AlexAltea/nucleus/blob/master/nucleus/gpu/rsx_pgraph.cpp + union qword + { + u64 dword[2]; + u32 word[4]; + }; + + struct HashVertexProgram + { + size_t operator()(const std::vector &program) const + { + // 64-bit Fowler/Noll/Vo FNV-1a hash code + size_t hash = 0xCBF29CE484222325ULL; + const qword *instbuffer = (const qword*)program.data(); + size_t instIndex = 0; + bool end = false; + for (unsigned i = 0; i < program.size() / 4; i++) + { + const qword inst = instbuffer[instIndex]; + hash ^= inst.dword[0]; + hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) + (hash << 8) + (hash << 40); + hash ^= inst.dword[1]; + hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) + (hash << 8) + (hash << 40); + instIndex++; + } + return hash; + } + }; + + + struct VertexProgramCompare + { + bool operator()(const std::vector &binary1, const std::vector &binary2) const + { + if (binary1.size() != binary2.size()) return false; + const qword *instBuffer1 = (const qword*)binary1.data(); + const qword *instBuffer2 = (const qword*)binary2.data(); + size_t instIndex = 0; + for (unsigned i = 0; i < binary1.size() / 4; i++) + { + const qword& inst1 = instBuffer1[instIndex]; + const qword& inst2 = instBuffer2[instIndex]; + if (inst1.dword[0] != inst2.dword[0] || inst1.dword[1] != inst2.dword[1]) + return false; + instIndex++; + } + return true; + } + }; + + struct FragmentProgramUtil + { + /** + * returns true if the given source Operand is a constant + */ + static bool isConstant(u32 sourceOperand) + { + return ((sourceOperand >> 8) & 0x3) == 2; + } + + /** + * RSX fragment program constants are inlined inside shader code. + * This function takes an instruction from a fragment program and + * returns an equivalent instruction where inlined constants + * are masked. + * This allows to hash/compare fragment programs even if their + * inlined constants are modified inbetween + */ + static qword fragmentMaskConstant(const qword &initialQword) + { + qword result = initialQword; + if (isConstant(initialQword.word[1])) + result.word[1] = 0; + if (isConstant(initialQword.word[2])) + result.word[2] = 0; + if (isConstant(initialQword.word[3])) + result.word[3] = 0; + return result; + } + + static + size_t getFPBinarySize(void *ptr) + { + const qword *instBuffer = (const qword*)ptr; + size_t instIndex = 0; + while (true) + { + const qword& inst = instBuffer[instIndex]; + bool isSRC0Constant = isConstant(inst.word[1]); + bool isSRC1Constant = isConstant(inst.word[2]); + bool isSRC2Constant = isConstant(inst.word[3]); + bool end = (inst.word[0] >> 8) & 0x1; + + if (isSRC0Constant || isSRC1Constant || isSRC2Constant) + { + instIndex += 2; + if (end) + return instIndex * 4 * 4; + continue; + } + instIndex++; + if (end) + return (instIndex)* 4 * 4; + } + } + }; + + struct HashFragmentProgram + { + size_t operator()(const void *program) const + { + // 64-bit Fowler/Noll/Vo FNV-1a hash code + size_t hash = 0xCBF29CE484222325ULL; + const qword *instbuffer = (const qword*)program; + size_t instIndex = 0; + while (true) + { + const qword& inst = instbuffer[instIndex]; + bool end = (inst.word[0] >> 8) & 0x1; + if (end) + return hash; + const qword& maskedInst = FragmentProgramUtil::fragmentMaskConstant(inst); + hash ^= maskedInst.dword[0]; + hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) + (hash << 8) + (hash << 40); + hash ^= maskedInst.dword[1]; + hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) + (hash << 8) + (hash << 40); + instIndex++; + // Skip constants + if (FragmentProgramUtil::isConstant(inst.word[1]) || + FragmentProgramUtil::isConstant(inst.word[2]) || + FragmentProgramUtil::isConstant(inst.word[3])) + instIndex++; + } + return 0; + } + }; + + struct FragmentProgramCompare + { + bool operator()(const void *binary1, const void *binary2) const + { + const qword *instBuffer1 = (const qword*)binary1; + const qword *instBuffer2 = (const qword*)binary2; + size_t instIndex = 0; + while (true) + { + const qword& inst1 = instBuffer1[instIndex]; + const qword& inst2 = instBuffer2[instIndex]; + bool end = ((inst1.word[0] >> 8) & 0x1) && ((inst2.word[0] >> 8) & 0x1); + if (end) + return true; + + const qword& maskedInst1 = FragmentProgramUtil::fragmentMaskConstant(inst1); + const qword& maskedInst2 = FragmentProgramUtil::fragmentMaskConstant(inst2); + + if (maskedInst1.dword[0] != maskedInst2.dword[0] || maskedInst1.dword[1] != maskedInst2.dword[1]) + return false; + instIndex++; + // Skip constants + if (FragmentProgramUtil::isConstant(inst1.word[1]) || + FragmentProgramUtil::isConstant(inst1.word[2]) || + FragmentProgramUtil::isConstant(inst1.word[3])) + instIndex++; + } + } + }; +} + + +/** +* Cache for program help structure (blob, string...) +* The class is responsible for creating the object so the state only has to call getGraphicPipelineState +* Template argument is a struct which has the following type declaration : +* - a typedef VertexProgramData to a type that encapsulate vertex program info. It should provide an Id member. +* - a typedef FragmentProgramData to a types that encapsulate fragment program info. It should provide an Id member and a fragment constant offset vector. +* - a typedef PipelineData encapsulating monolithic program. +* - a typedef PipelineProperties to a type that encapsulate various state info relevant to program compilation (alpha test, primitive type,...) +* - a typedef ExtraData type that will be passed to the buildProgram function. +* It should also contains the following function member : +* - static void RecompileFragmentProgram(RSXFragmentProgram *RSXFP, FragmentProgramData& fragmentProgramData, size_t ID); +* - static void RecompileVertexProgram(RSXVertexProgram *RSXVP, VertexProgramData& vertexProgramData, size_t ID); +* - static PipelineData *BuildProgram(VertexProgramData &vertexProgramData, FragmentProgramData &fragmentProgramData, const PipelineProperties &pipelineProperties, const ExtraData& extraData); +* - void DeleteProgram(PipelineData *ptr); +*/ +template +class ProgramStateCache +{ +private: + typedef std::unordered_map, typename BackendTraits::VertexProgramData, ProgramHashUtil::HashVertexProgram, ProgramHashUtil::VertexProgramCompare> binary2VS; + typedef std::unordered_map binary2FS; + binary2VS m_cacheVS; + binary2FS m_cacheFS; + + size_t m_currentShaderId; + std::vector dummyFragmentConstantCache; + + struct PSOKey + { + u32 vpIdx; + u32 fpIdx; + typename BackendTraits::PipelineProperties properties; + }; + + struct PSOKeyHash + { + size_t operator()(const PSOKey &key) const + { + size_t hashValue = 0; + hashValue ^= std::hash()(key.vpIdx); + return hashValue; + } + }; + + struct PSOKeyCompare + { + size_t operator()(const PSOKey &key1, const PSOKey &key2) const + { + return (key1.vpIdx == key2.vpIdx) && (key1.fpIdx == key2.fpIdx) && (key1.properties == key2.properties); + } + }; + + std::unordered_map m_cachePSO; + + typename BackendTraits::FragmentProgramData& SearchFp(RSXFragmentProgram* rsx_fp, bool& found) + { + typename binary2FS::iterator It = m_cacheFS.find(vm::get_ptr(rsx_fp->addr)); + if (It != m_cacheFS.end()) + { + found = true; + return It->second; + } + found = false; + LOG_WARNING(RSX, "FP not found in buffer!"); + size_t actualFPSize = ProgramHashUtil::FragmentProgramUtil::getFPBinarySize(vm::get_ptr(rsx_fp->addr)); + void *fpShadowCopy = malloc(actualFPSize); + memcpy(fpShadowCopy, vm::get_ptr(rsx_fp->addr), actualFPSize); + typename BackendTraits::FragmentProgramData &newShader = m_cacheFS[fpShadowCopy]; + BackendTraits::RecompileFragmentProgram(rsx_fp, newShader, m_currentShaderId++); + + return newShader; + } + + typename BackendTraits::VertexProgramData& SearchVp(RSXVertexProgram* rsx_vp, bool &found) + { + typename binary2VS::iterator It = m_cacheVS.find(rsx_vp->data); + if (It != m_cacheVS.end()) + { + found = true; + return It->second; + } + found = false; + LOG_WARNING(RSX, "VP not found in buffer!"); + typename BackendTraits::VertexProgramData& newShader = m_cacheVS[rsx_vp->data]; + BackendTraits::RecompileVertexProgram(rsx_vp, newShader, m_currentShaderId++); + + return newShader; + } + + typename BackendTraits::PipelineData *GetProg(const PSOKey &psoKey) const + { + typename std::unordered_map::const_iterator It = m_cachePSO.find(psoKey); + if (It == m_cachePSO.end()) + return nullptr; + return It->second; + } + + void Add(typename BackendTraits::PipelineData *prog, const PSOKey& PSOKey) + { + m_cachePSO.insert(std::make_pair(PSOKey, prog)); + } + +public: + ProgramStateCache() : m_currentShaderId(0) {} + ~ProgramStateCache() + { + for (auto pair : m_cachePSO) + BackendTraits::DeleteProgram(pair.second); + for (auto pair : m_cacheFS) + free(pair.first); + } + + typename BackendTraits::PipelineData *getGraphicPipelineState( + RSXVertexProgram *vertexShader, + RSXFragmentProgram *fragmentShader, + const typename BackendTraits::PipelineProperties &pipelineProperties, + const typename BackendTraits::ExtraData& extraData + ) + { + typename BackendTraits::PipelineData *result = nullptr; + bool fpFound, vpFound; + typename BackendTraits::VertexProgramData &vertexProg = SearchVp(vertexShader, vpFound); + typename BackendTraits::FragmentProgramData &fragmentProg = SearchFp(fragmentShader, fpFound); + + if (fpFound && vpFound) + { + result = GetProg({ vertexProg.id, fragmentProg.id, pipelineProperties }); + } + + if (result != nullptr) + return result; + else + { + LOG_WARNING(RSX, "Add program :"); + LOG_WARNING(RSX, "*** vp id = %d", vertexProg.id); + LOG_WARNING(RSX, "*** fp id = %d", fragmentProg.id); + + result = BackendTraits::BuildProgram(vertexProg, fragmentProg, pipelineProperties, extraData); + Add(result, { vertexProg.id, fragmentProg.id, pipelineProperties }); + } + return result; + } + + const std::vector &getFragmentConstantOffsetsCache(const RSXFragmentProgram *fragmentShader) const + { + typename binary2FS::const_iterator It = m_cacheFS.find(vm::get_ptr(fragmentShader->addr)); + if (It != m_cacheFS.end()) + return It->second.FragmentConstantOffsetCache; + LOG_ERROR(RSX, "Can't retrieve constant offset cache"); + return dummyFragmentConstantCache; + } +}; \ No newline at end of file diff --git a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp index 0750057991..f203f3be05 100644 --- a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp @@ -105,10 +105,10 @@ std::string GLFragmentDecompilerThread::AddConst() auto data = vm::ptr::make(m_addr + m_size + 4 * sizeof(u32)); m_offset = 2 * 4 * sizeof(u32); - u32 x = GetData(data[0]); - u32 y = GetData(data[1]); - u32 z = GetData(data[2]); - u32 w = GetData(data[3]); + u32 x = 0;//GetData(data[0]); + u32 y = 0;//GetData(data[1]); + u32 z = 0;//GetData(data[2]); + u32 w = 0;//GetData(data[3]); return m_parr.AddParam(PARAM_UNIFORM, "vec4", name, std::string("vec4(") + std::to_string((float&)x) + ", " + std::to_string((float&)y) + ", " + std::to_string((float&)z) + ", " + std::to_string((float&)w) + ")"); @@ -613,7 +613,7 @@ void GLFragmentDecompilerThread::Task() m_code_level = 1; m_shader = BuildCode(); main.clear(); - m_parr.params.clear(); +// m_parr.params.clear(); } GLFragmentProgram::GLFragmentProgram() @@ -673,7 +673,7 @@ void GLFragmentProgram::DecompileAsync(RSXFragmentProgram& prog) void GLFragmentProgram::Compile() { - if (id) + if (id) { glDeleteShader(id); } @@ -707,6 +707,15 @@ void GLFragmentProgram::Compile() LOG_NOTICE(RSX, shader.c_str()); // Log the text of the shader that failed to compile Emu.Pause(); // Pause the emulator, we can't really continue from here } + for (const GLParamType& PT : parr.params) + { + if (PT.flag != PARAM_UNIFORM) continue; + for (const GLParamItem PI : PT.items) + { + size_t offset = atoi(PI.name.c_str() + 2); + FragmentConstantOffsetCache.push_back(offset); + } + } } void GLFragmentProgram::Delete() diff --git a/rpcs3/Emu/RSX/GL/GLFragmentProgram.h b/rpcs3/Emu/RSX/GL/GLFragmentProgram.h index aa7acdad9f..3430e85a39 100644 --- a/rpcs3/Emu/RSX/GL/GLFragmentProgram.h +++ b/rpcs3/Emu/RSX/GL/GLFragmentProgram.h @@ -65,6 +65,7 @@ public: GLParamArray parr; u32 id; std::string shader; + std::vector FragmentConstantOffsetCache; /** * Decompile a fragment shader located in the PS3's Memory. This function operates synchronously. diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 317613183a..c723cd4e0d 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -1089,6 +1089,28 @@ void GLGSRender::InitFragmentData() return; } + // Get constant from fragment program + const std::vector &fragmentOffset = m_prog_buffer.getFragmentConstantOffsetsCache(m_cur_fragment_prog); + for (size_t offsetInFP : fragmentOffset) + { + auto data = vm::ptr::make(m_cur_fragment_prog->addr + (u32)offsetInFP); + + u32 c0 = (data[0] >> 16 | data[0] << 16); + u32 c1 = (data[1] >> 16 | data[1] << 16); + u32 c2 = (data[2] >> 16 | data[2] << 16); + u32 c3 = (data[3] >> 16 | data[3] << 16); + const std::string name = fmt::Format("fc%u", offsetInFP); + const int l = m_program.GetLocation(name); + checkForGlError("glGetUniformLocation " + name); + + float f0 = (float&)c0; + float f1 = (float&)c1; + float f2 = (float&)c2; + float f3 = (float&)c3; + glUniform4f(l, f0, f1, f2, f3); + checkForGlError("glUniform4f " + name + fmt::Format(" %u [%f %f %f %f]", l, f0, f1, f2, f3)); + } + for (const RSXTransformConstant& c : m_fragment_constants) { u32 id = c.id - m_cur_fragment_prog->offset; @@ -1103,6 +1125,7 @@ void GLGSRender::InitFragmentData() checkForGlError("glUniform4f " + name + fmt::Format(" %u [%f %f %f %f]", l, c.x, c.y, c.z, c.w)); } + //if (m_fragment_constants.GetCount()) // LOG_NOTICE(HLE, ""); } @@ -1123,88 +1146,9 @@ bool GLGSRender::LoadProgram() return false; } - m_fp_buf_num = m_prog_buffer.SearchFp(*m_cur_fragment_prog, m_fragment_prog); - m_vp_buf_num = m_prog_buffer.SearchVp(*m_cur_vertex_prog, m_vertex_prog); - - if (m_fp_buf_num == -1) - { - LOG_WARNING(RSX, "FP not found in buffer!"); - m_fragment_prog.Decompile(*m_cur_fragment_prog); - m_fragment_prog.Compile(); - checkForGlError("m_fragment_prog.Compile"); - - // TODO: This shouldn't use current dir - fs::file("./FragmentProgram.txt", o_write | o_create | o_trunc).write(m_fragment_prog.shader.c_str(), m_fragment_prog.shader.size()); - } - - if (m_vp_buf_num == -1) - { - LOG_WARNING(RSX, "VP not found in buffer!"); - m_vertex_prog.Decompile(*m_cur_vertex_prog); - m_vertex_prog.Compile(); - checkForGlError("m_vertex_prog.Compile"); - - // TODO: This shouldn't use current dir - fs::file("./VertexProgram.txt", o_write | o_create | o_trunc).write(m_vertex_prog.shader.c_str(), m_vertex_prog.shader.size()); - } - - if (m_fp_buf_num != -1 && m_vp_buf_num != -1) - { - m_program.id = m_prog_buffer.GetProg(m_fp_buf_num, m_vp_buf_num); - } - - if (m_program.id) - { - // RSX Debugger: Check if this program was modified and update it - if (Ini.GSLogPrograms.GetValue()) - { - for (auto& program : m_debug_programs) - { - if (program.id == m_program.id && program.modified) - { - // TODO: This isn't working perfectly. Is there any better/shorter way to update the program - m_vertex_prog.shader = program.vp_shader; - m_fragment_prog.shader = program.fp_shader; - m_vertex_prog.Wait(); - m_vertex_prog.Compile(); - checkForGlError("m_vertex_prog.Compile"); - m_fragment_prog.Wait(); - m_fragment_prog.Compile(); - checkForGlError("m_fragment_prog.Compile"); - glAttachShader(m_program.id, m_vertex_prog.id); - glAttachShader(m_program.id, m_fragment_prog.id); - glLinkProgram(m_program.id); - checkForGlError("glLinkProgram"); - glDetachShader(m_program.id, m_vertex_prog.id); - glDetachShader(m_program.id, m_fragment_prog.id); - program.vp_id = m_vertex_prog.id; - program.fp_id = m_fragment_prog.id; - program.modified = false; - } - } - } - m_program.Use(); - } - else - { - m_program.Create(m_vertex_prog.id, m_fragment_prog.id); - checkForGlError("m_program.Create"); - m_prog_buffer.Add(m_program, m_fragment_prog, *m_cur_fragment_prog, m_vertex_prog, *m_cur_vertex_prog); - checkForGlError("m_prog_buffer.Add"); - m_program.Use(); - - // RSX Debugger - if (Ini.GSLogPrograms.GetValue()) - { - RSXDebuggerProgram program; - program.id = m_program.id; - program.vp_id = m_vertex_prog.id; - program.fp_id = m_fragment_prog.id; - program.vp_shader = m_vertex_prog.shader; - program.fp_shader = m_fragment_prog.shader; - m_debug_programs.push_back(program); - } - } + GLProgram *result = m_prog_buffer.getGraphicPipelineState(m_cur_vertex_prog, m_cur_fragment_prog, nullptr, nullptr); + m_program.id = result->id; + m_program.Use(); return true; } @@ -1477,7 +1421,6 @@ void GLGSRender::OnExitThread() m_fbo.Delete(); m_vbo.Delete(); m_vao.Delete(); - m_prog_buffer.Clear(); } void GLGSRender::OnReset() diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.h b/rpcs3/Emu/RSX/GL/GLGSRender.h index 409f9ae124..495f940172 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.h +++ b/rpcs3/Emu/RSX/GL/GLGSRender.h @@ -1,16 +1,13 @@ #pragma once #include "Emu/RSX/GSRender.h" #include "GLBuffers.h" -#include "GLProgramBuffer.h" - -#pragma comment(lib, "opengl32.lib") #define RSX_DEBUG 1 -extern GLenum g_last_gl_error; -void printGlError(GLenum err, const char* situation); -void printGlError(GLenum err, const std::string& situation); -u32 LinearToSwizzleAddress(u32 x, u32 y, u32 z, u32 log2_width, u32 log2_height, u32 log2_depth); + +#include "GLProgramBuffer.h" + +#pragma comment(lib, "opengl32.lib") #if RSX_DEBUG #define checkForGlError(sit) if((g_last_gl_error = glGetError()) != GL_NO_ERROR) printGlError(g_last_gl_error, sit) @@ -18,6 +15,12 @@ u32 LinearToSwizzleAddress(u32 x, u32 y, u32 z, u32 log2_width, u32 log2_height, #define checkForGlError(sit) #endif +extern GLenum g_last_gl_error; +void printGlError(GLenum err, const char* situation); +void printGlError(GLenum err, const std::string& situation); +u32 LinearToSwizzleAddress(u32 x, u32 y, u32 z, u32 log2_width, u32 log2_height, u32 log2_depth); + + class GLTexture { u32 m_id; diff --git a/rpcs3/Emu/RSX/GL/GLProgram.cpp b/rpcs3/Emu/RSX/GL/GLProgram.cpp index da5f7e6952..8ead41e479 100644 --- a/rpcs3/Emu/RSX/GL/GLProgram.cpp +++ b/rpcs3/Emu/RSX/GL/GLProgram.cpp @@ -38,7 +38,6 @@ void GLProgram::Create(const u32 vp, const u32 fp) Delete(); id = glCreateProgram(); - glAttachShader(id, vp); glAttachShader(id, fp); diff --git a/rpcs3/Emu/RSX/GL/GLProgramBuffer.cpp b/rpcs3/Emu/RSX/GL/GLProgramBuffer.cpp index f3a358940d..3df737bd0c 100644 --- a/rpcs3/Emu/RSX/GL/GLProgramBuffer.cpp +++ b/rpcs3/Emu/RSX/GL/GLProgramBuffer.cpp @@ -2,133 +2,4 @@ #include "Utilities/Log.h" #include "Emu/Memory/Memory.h" -#include "GLProgramBuffer.h" - -int GLProgramBuffer::SearchFp(const RSXFragmentProgram& rsx_fp, GLFragmentProgram& gl_fp) -{ - for(u32 i=0; i(rsx_fp.addr), m_buf[i].fp_data.size()) != 0) continue; - - gl_fp.id = m_buf[i].fp_id; - gl_fp.shader = m_buf[i].fp_shader.c_str(); - - return i; - } - - return -1; -} - -int GLProgramBuffer::SearchVp(const RSXVertexProgram& rsx_vp, GLVertexProgram& gl_vp) -{ - for(u32 i=0; i(rsx_fp.addr), vm::get_ptr(rsx_fp.addr + rsx_fp.size)); - new_buf.vp_data = rsx_vp.data; - - new_buf.vp_shader = gl_vp.shader; - new_buf.fp_shader = gl_fp.shader; - - m_buf.push_back(new_buf); -} - -void GLProgramBuffer::Clear() -{ - for (u32 i = 0; i < m_buf.size(); ++i) - { - glDetachShader(m_buf[i].prog_id, m_buf[i].fp_id); - glDetachShader(m_buf[i].prog_id, m_buf[i].vp_id); - glDeleteShader(m_buf[i].fp_id); - glDeleteShader(m_buf[i].vp_id); - glDeleteProgram(m_buf[i].prog_id); - - m_buf[i].fp_data.clear(); - m_buf[i].vp_data.clear(); - - m_buf[i].vp_shader.clear(); - m_buf[i].fp_shader.clear(); - } - - m_buf.clear(); -} +//#include "GLProgramBuffer.h" \ No newline at end of file diff --git a/rpcs3/Emu/RSX/GL/GLProgramBuffer.h b/rpcs3/Emu/RSX/GL/GLProgramBuffer.h index 5299313e6f..9059520510 100644 --- a/rpcs3/Emu/RSX/GL/GLProgramBuffer.h +++ b/rpcs3/Emu/RSX/GL/GLProgramBuffer.h @@ -1,29 +1,63 @@ #pragma once #include "GLProgram.h" +#include "../Common/ProgramStateCache.h" +#include "Utilities/File.h" -struct GLBufferInfo +struct GLTraits { - u32 prog_id; - u32 fp_id; - u32 vp_id; - std::vector fp_data; - std::vector vp_data; - std::string fp_shader; - std::string vp_shader; + typedef GLVertexProgram VertexProgramData; + typedef GLFragmentProgram FragmentProgramData; + typedef GLProgram PipelineData; + typedef void* PipelineProperties; + typedef void* ExtraData; + + static + void RecompileFragmentProgram(RSXFragmentProgram *RSXFP, FragmentProgramData& fragmentProgramData, size_t ID) + { + fragmentProgramData.Decompile(*RSXFP); + fragmentProgramData.Compile(); + //checkForGlError("m_fragment_prog.Compile"); + + // TODO: This shouldn't use current dir + fs::file("./FragmentProgram.txt", o_write | o_create | o_trunc).write(fragmentProgramData.shader.c_str(), fragmentProgramData.shader.size()); + } + + static + void RecompileVertexProgram(RSXVertexProgram *RSXVP, VertexProgramData& vertexProgramData, size_t ID) + { + vertexProgramData.Decompile(*RSXVP); + vertexProgramData.Compile(); + //checkForGlError("m_vertex_prog.Compile"); + + // TODO: This shouldn't use current dir + fs::file("./VertexProgram.txt", o_write | o_create | o_trunc).write(vertexProgramData.shader.c_str(), vertexProgramData.shader.size()); + } + + static + PipelineData *BuildProgram(VertexProgramData &vertexProgramData, FragmentProgramData &fragmentProgramData, const PipelineProperties &pipelineProperties, const ExtraData& extraData) + { + GLProgram *result = new GLProgram(); + result->Create(vertexProgramData.id, fragmentProgramData.id); + //checkForGlError("m_program.Create"); + result->Use(); + + LOG_NOTICE(RSX, "*** prog id = %d", result->id); + LOG_NOTICE(RSX, "*** vp id = %d", vertexProgramData.id); + LOG_NOTICE(RSX, "*** fp id = %d", fragmentProgramData.id); + + LOG_NOTICE(RSX, "*** vp shader = \n%s", vertexProgramData.shader.c_str()); + LOG_NOTICE(RSX, "*** fp shader = \n%s", fragmentProgramData.shader.c_str()); + + return result; + } + + static + void DeleteProgram(PipelineData *ptr) + { + ptr->Delete(); + } }; -struct GLProgramBuffer +class GLProgramBuffer : public ProgramStateCache { - std::vector m_buf; - - int SearchFp(const RSXFragmentProgram& rsx_fp, GLFragmentProgram& gl_fp); - int SearchVp(const RSXVertexProgram& rsx_vp, GLVertexProgram& gl_vp); - - bool CmpVP(const u32 a, const u32 b) const; - bool CmpFP(const u32 a, const u32 b) const; - - u32 GetProg(u32 fp, u32 vp) const; - - void Add(GLProgram& prog, GLFragmentProgram& gl_fp, RSXFragmentProgram& rsx_fp, GLVertexProgram& gl_vp, RSXVertexProgram& rsx_vp); - void Clear(); }; diff --git a/rpcs3/Emu/RSX/GL/GLVertexProgram.cpp b/rpcs3/Emu/RSX/GL/GLVertexProgram.cpp index ecada28746..291fc4d6e7 100644 --- a/rpcs3/Emu/RSX/GL/GLVertexProgram.cpp +++ b/rpcs3/Emu/RSX/GL/GLVertexProgram.cpp @@ -822,7 +822,7 @@ void GLVertexProgram::DecompileAsync(RSXVertexProgram& prog) void GLVertexProgram::Compile() { - if (id) + if (id) { glDeleteShader(id); } diff --git a/rpcs3/Gui/ConLogFrame.cpp b/rpcs3/Gui/ConLogFrame.cpp index 55e77b7028..73260864a6 100644 --- a/rpcs3/Gui/ConLogFrame.cpp +++ b/rpcs3/Gui/ConLogFrame.cpp @@ -76,16 +76,16 @@ struct wxWriter : Log::LogListener { switch (msg.mServerity) { - case Log::Notice: + case Log::LogSeverityNotice: llogcon->SetDefaultStyle(m_color_white); break; - case Log::Warning: + case Log::LogSeverityWarning: llogcon->SetDefaultStyle(m_color_yellow); break; - case Log::Error: + case Log::LogSeverityError: llogcon->SetDefaultStyle(m_color_red); break; - case Log::Success: + case Log::LogSeveritySuccess: llogcon->SetDefaultStyle(m_color_green); break; default: diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 5b35d41c97..59136ac526 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -416,6 +416,7 @@ + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index facf1494db..3b8b20c764 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -90,6 +90,9 @@ {368770cf-c8d9-4f4a-9ac3-5bdf48101ffe} + + {2a8841dc-bce0-41bb-9fcb-5bf1f8dda213} + @@ -1549,5 +1552,8 @@ Utilities + + Emu\GPU\RSX\Common + \ No newline at end of file