mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-02-01 04:51:49 +01:00
rsx/common/d3d12/gl: Clean ProgramStateCache
Use a_b_c format. Use using = Use tuple as output Use RAII to delete program safely Ensure const correctness.
This commit is contained in:
parent
cc1efd2a46
commit
bab52c132d
@ -334,7 +334,9 @@ public:
|
|||||||
u32 size;
|
u32 size;
|
||||||
u32 ctrl = (vmfprog.outputFromH0 ? 0 : 0x40) | (vmfprog.depthReplace ? 0xe : 0);
|
u32 ctrl = (vmfprog.outputFromH0 ? 0 : 0x40) | (vmfprog.depthReplace ? 0xe : 0);
|
||||||
std::vector<texture_dimension> td;
|
std::vector<texture_dimension> td;
|
||||||
GLFragmentDecompilerThread(m_glsl_shader, param_array, ptr + vmprog.ucode, size, ctrl, td).Task();
|
RSXFragmentProgram prog;
|
||||||
|
prog.size = 0, prog.addr = ptr + vmprog.ucode, prog.offset = 0, prog.ctrl = ctrl;
|
||||||
|
GLFragmentDecompilerThread(m_glsl_shader, param_array, prog, size).Task();
|
||||||
vm::close();
|
vm::close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -383,7 +385,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
TaskVP();
|
TaskVP();
|
||||||
GLVertexDecompilerThread(m_data, m_glsl_shader, param_array).Task();
|
RSXVertexProgram prog;
|
||||||
|
prog.data = m_data;
|
||||||
|
GLVertexDecompilerThread(prog, m_glsl_shader, param_array).Task();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
|
|
||||||
#include "FragmentProgramDecompiler.h"
|
#include "FragmentProgramDecompiler.h"
|
||||||
|
|
||||||
FragmentProgramDecompiler::FragmentProgramDecompiler(u32 addr, u32& size, u32 ctrl, const std::vector<texture_dimension> &texture_dimensions) :
|
FragmentProgramDecompiler::FragmentProgramDecompiler(const RSXFragmentProgram &prog, u32& size) :
|
||||||
m_addr(addr),
|
m_addr(prog.addr),
|
||||||
m_size(size),
|
m_size(size),
|
||||||
m_const_index(0),
|
m_const_index(0),
|
||||||
m_location(0),
|
m_location(0),
|
||||||
m_ctrl(ctrl),
|
m_ctrl(prog.ctrl),
|
||||||
m_texture_dimensions(texture_dimensions)
|
m_texture_dimensions(prog.texture_dimensions)
|
||||||
{
|
{
|
||||||
m_size = 0;
|
m_size = 0;
|
||||||
}
|
}
|
||||||
|
@ -113,6 +113,8 @@ protected:
|
|||||||
virtual void insertMainEnd(std::stringstream &OS) = 0;
|
virtual void insertMainEnd(std::stringstream &OS) = 0;
|
||||||
public:
|
public:
|
||||||
ParamArray m_parr;
|
ParamArray m_parr;
|
||||||
FragmentProgramDecompiler(u32 addr, u32& size, u32 ctrl, const std::vector<texture_dimension> &texture_dimensions);
|
FragmentProgramDecompiler(const RSXFragmentProgram &prog, u32& size);
|
||||||
|
FragmentProgramDecompiler(const FragmentProgramDecompiler&) = delete;
|
||||||
|
FragmentProgramDecompiler(FragmentProgramDecompiler&&) = delete;
|
||||||
std::string Decompile();
|
std::string Decompile();
|
||||||
};
|
};
|
||||||
|
123
rpcs3/Emu/RSX/Common/ProgramStateCache.cpp
Normal file
123
rpcs3/Emu/RSX/Common/ProgramStateCache.cpp
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
#include "stdafx.h"
|
||||||
|
#include "ProgramStateCache.h"
|
||||||
|
|
||||||
|
using namespace program_hash_util;
|
||||||
|
|
||||||
|
size_t vertex_program_hash::operator()(const std::vector<u32> &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;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vertex_program_compare::operator()(const std::vector<u32> &binary1, const std::vector<u32> &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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool fragment_program_utils::is_constant(u32 sourceOperand)
|
||||||
|
{
|
||||||
|
return ((sourceOperand >> 8) & 0x3) == 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t fragment_program_utils::get_fragment_program_ucode_size(void *ptr)
|
||||||
|
{
|
||||||
|
const qword *instBuffer = (const qword*)ptr;
|
||||||
|
size_t instIndex = 0;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
const qword& inst = instBuffer[instIndex];
|
||||||
|
bool isSRC0Constant = is_constant(inst.word[1]);
|
||||||
|
bool isSRC1Constant = is_constant(inst.word[2]);
|
||||||
|
bool isSRC2Constant = is_constant(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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t fragment_program_hash::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];
|
||||||
|
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++;
|
||||||
|
// Skip constants
|
||||||
|
if (fragment_program_utils::is_constant(inst.word[1]) ||
|
||||||
|
fragment_program_utils::is_constant(inst.word[2]) ||
|
||||||
|
fragment_program_utils::is_constant(inst.word[3]))
|
||||||
|
instIndex++;
|
||||||
|
|
||||||
|
bool end = (inst.word[0] >> 8) & 0x1;
|
||||||
|
if (end)
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fragment_program_compare::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];
|
||||||
|
|
||||||
|
if (inst1.dword[0] != inst2.dword[0] || inst1.dword[1] != inst2.dword[1])
|
||||||
|
return false;
|
||||||
|
instIndex++;
|
||||||
|
// Skip constants
|
||||||
|
if (fragment_program_utils::is_constant(inst1.word[1]) ||
|
||||||
|
fragment_program_utils::is_constant(inst1.word[2]) ||
|
||||||
|
fragment_program_utils::is_constant(inst1.word[3]))
|
||||||
|
instIndex++;
|
||||||
|
|
||||||
|
bool end = ((inst1.word[0] >> 8) & 0x1) && ((inst2.word[0] >> 8) & 0x1);
|
||||||
|
if (end)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "Emu/RSX/RSXFragmentProgram.h"
|
#include "Emu/RSX/RSXFragmentProgram.h"
|
||||||
#include "Emu/RSX/RSXVertexProgram.h"
|
#include "Emu/RSX/RSXVertexProgram.h"
|
||||||
|
#include "Emu/Memory/vm.h"
|
||||||
|
|
||||||
|
|
||||||
enum class SHADER_TYPE
|
enum class SHADER_TYPE
|
||||||
@ -10,7 +11,7 @@ enum class SHADER_TYPE
|
|||||||
SHADER_TYPE_FRAGMENT
|
SHADER_TYPE_FRAGMENT
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace ProgramHashUtil
|
namespace program_hash_util
|
||||||
{
|
{
|
||||||
// Based on
|
// Based on
|
||||||
// https://github.com/AlexAltea/nucleus/blob/master/nucleus/gpu/rsx_pgraph.cpp
|
// https://github.com/AlexAltea/nucleus/blob/master/nucleus/gpu/rsx_pgraph.cpp
|
||||||
@ -20,142 +21,34 @@ namespace ProgramHashUtil
|
|||||||
u32 word[4];
|
u32 word[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct HashVertexProgram
|
struct vertex_program_hash
|
||||||
{
|
{
|
||||||
size_t operator()(const std::vector<u32> &program) const
|
size_t operator()(const std::vector<u32> &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 vertex_program_compare
|
||||||
struct VertexProgramCompare
|
|
||||||
{
|
{
|
||||||
bool operator()(const std::vector<u32> &binary1, const std::vector<u32> &binary2) const
|
bool operator()(const std::vector<u32> &binary1, const std::vector<u32> &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
|
struct fragment_program_utils
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* returns true if the given source Operand is a constant
|
* returns true if the given source Operand is a constant
|
||||||
*/
|
*/
|
||||||
static bool isConstant(u32 sourceOperand)
|
static bool is_constant(u32 sourceOperand);
|
||||||
{
|
|
||||||
return ((sourceOperand >> 8) & 0x3) == 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
static size_t get_fragment_program_ucode_size(void *ptr);
|
||||||
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
|
struct fragment_program_hash
|
||||||
{
|
{
|
||||||
size_t operator()(const void *program) const
|
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];
|
|
||||||
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++;
|
|
||||||
// Skip constants
|
|
||||||
if (FragmentProgramUtil::isConstant(inst.word[1]) ||
|
|
||||||
FragmentProgramUtil::isConstant(inst.word[2]) ||
|
|
||||||
FragmentProgramUtil::isConstant(inst.word[3]))
|
|
||||||
instIndex++;
|
|
||||||
|
|
||||||
bool end = (inst.word[0] >> 8) & 0x1;
|
|
||||||
if (end)
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FragmentProgramCompare
|
struct fragment_program_compare
|
||||||
{
|
{
|
||||||
bool operator()(const void *binary1, const void *binary2) const
|
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];
|
|
||||||
|
|
||||||
if (inst1.dword[0] != inst2.dword[0] || inst1.dword[1] != inst2.dword[1])
|
|
||||||
return false;
|
|
||||||
instIndex++;
|
|
||||||
// Skip constants
|
|
||||||
if (FragmentProgramUtil::isConstant(inst1.word[1]) ||
|
|
||||||
FragmentProgramUtil::isConstant(inst1.word[2]) ||
|
|
||||||
FragmentProgramUtil::isConstant(inst1.word[3]))
|
|
||||||
instIndex++;
|
|
||||||
|
|
||||||
bool end = ((inst1.word[0] >> 8) & 0x1) && ((inst2.word[0] >> 8) & 0x1);
|
|
||||||
if (end)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,193 +63,170 @@ namespace ProgramHashUtil
|
|||||||
* - a typedef PipelineProperties to a type that encapsulate various state info relevant to program compilation (alpha test, primitive type,...)
|
* - 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.
|
* - a typedef ExtraData type that will be passed to the buildProgram function.
|
||||||
* It should also contains the following function member :
|
* It should also contains the following function member :
|
||||||
* - static void RecompileFragmentProgram(RSXFragmentProgram *RSXFP, FragmentProgramData& fragmentProgramData, size_t ID);
|
* - static void recompile_fragment_program(RSXFragmentProgram *RSXFP, FragmentProgramData& fragmentProgramData, size_t ID);
|
||||||
* - static void RecompileVertexProgram(RSXVertexProgram *RSXVP, VertexProgramData& vertexProgramData, size_t ID);
|
* - static void recompile_vertex_program(RSXVertexProgram *RSXVP, VertexProgramData& vertexProgramData, size_t ID);
|
||||||
* - static PipelineData *BuildProgram(VertexProgramData &vertexProgramData, FragmentProgramData &fragmentProgramData, const PipelineProperties &pipelineProperties, const ExtraData& extraData);
|
* - static PipelineData build_program(VertexProgramData &vertexProgramData, FragmentProgramData &fragmentProgramData, const PipelineProperties &pipelineProperties, const ExtraData& extraData);
|
||||||
* - void DeleteProgram(PipelineData *ptr);
|
|
||||||
*/
|
*/
|
||||||
template<typename BackendTraits>
|
template<typename backend_traits>
|
||||||
class ProgramStateCache
|
class program_state_cache
|
||||||
{
|
{
|
||||||
private:
|
using pipeline_storage_type = typename backend_traits::pipeline_storage_type;
|
||||||
typedef std::unordered_map<std::vector<u32>, typename BackendTraits::VertexProgramData, ProgramHashUtil::HashVertexProgram, ProgramHashUtil::VertexProgramCompare> binary2VS;
|
using pipeline_properties = typename backend_traits::pipeline_properties;
|
||||||
typedef std::unordered_map<void *, typename BackendTraits::FragmentProgramData, ProgramHashUtil::HashFragmentProgram, ProgramHashUtil::FragmentProgramCompare> binary2FS;
|
using vertex_program_type = typename backend_traits::vertex_program_type;
|
||||||
binary2VS m_cacheVS;
|
using fragment_program_type = typename backend_traits::fragment_program_type;
|
||||||
binary2FS m_cacheFS;
|
|
||||||
|
|
||||||
size_t m_currentShaderId;
|
using binary_to_vertex_program = std::unordered_map<std::vector<u32>, vertex_program_type, program_hash_util::vertex_program_hash, program_hash_util::vertex_program_compare> ;
|
||||||
std::vector<size_t> dummyFragmentConstantCache;
|
using binary_to_fragment_program = std::unordered_map<void *, fragment_program_type, program_hash_util::fragment_program_hash, program_hash_util::fragment_program_compare>;
|
||||||
|
|
||||||
struct PSOKey
|
|
||||||
|
struct pipeline_key
|
||||||
{
|
{
|
||||||
u32 vpIdx;
|
u32 vertex_program_id;
|
||||||
u32 fpIdx;
|
u32 fragment_program_id;
|
||||||
typename BackendTraits::PipelineProperties properties;
|
pipeline_properties properties;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PSOKeyHash
|
struct pipeline_key_hash
|
||||||
{
|
{
|
||||||
size_t operator()(const PSOKey &key) const
|
size_t operator()(const pipeline_key &key) const
|
||||||
{
|
{
|
||||||
size_t hashValue = 0;
|
size_t hashValue = 0;
|
||||||
hashValue ^= std::hash<unsigned>()(key.vpIdx);
|
hashValue ^= std::hash<unsigned>()(key.vertex_program_id);
|
||||||
hashValue ^= std::hash<unsigned>()(key.fpIdx);
|
hashValue ^= std::hash<unsigned>()(key.fragment_program_id);
|
||||||
hashValue ^= std::hash<typename BackendTraits::PipelineProperties>()(key.properties);
|
hashValue ^= std::hash<pipeline_properties>()(key.properties);
|
||||||
return hashValue;
|
return hashValue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PSOKeyCompare
|
struct pipeline_key_compare
|
||||||
{
|
{
|
||||||
size_t operator()(const PSOKey &key1, const PSOKey &key2) const
|
bool operator()(const pipeline_key &key1, const pipeline_key &key2) const
|
||||||
{
|
{
|
||||||
return (key1.vpIdx == key2.vpIdx) && (key1.fpIdx == key2.fpIdx) && (key1.properties == key2.properties);
|
return (key1.vertex_program_id == key2.vertex_program_id) && (key1.fragment_program_id == key2.fragment_program_id) && (key1.properties == key2.properties);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unordered_map<PSOKey, typename BackendTraits::PipelineData*, PSOKeyHash, PSOKeyCompare> m_cachePSO;
|
private:
|
||||||
|
size_t m_next_id = 0;
|
||||||
|
binary_to_vertex_program m_vertex_shader_cache;
|
||||||
|
binary_to_fragment_program m_fragment_shader_cache;
|
||||||
|
std::unordered_map <pipeline_key, pipeline_storage_type, pipeline_key_hash, pipeline_key_compare> m_storage;
|
||||||
|
|
||||||
typename BackendTraits::FragmentProgramData& SearchFp(RSXFragmentProgram* rsx_fp, bool& found)
|
/// bool here to inform that the program was preexisting.
|
||||||
|
std::tuple<const vertex_program_type&, bool> search_vertex_program(const RSXVertexProgram& rsx_vp)
|
||||||
{
|
{
|
||||||
typename binary2FS::iterator It = m_cacheFS.find(vm::base(rsx_fp->addr));
|
const auto& I = m_vertex_shader_cache.find(rsx_vp.data);
|
||||||
if (It != m_cacheFS.end())
|
if (I != m_vertex_shader_cache.end())
|
||||||
{
|
{
|
||||||
found = true;
|
return std::forward_as_tuple(I->second, true);
|
||||||
return It->second;
|
|
||||||
}
|
}
|
||||||
found = false;
|
LOG_NOTICE(RSX, "VP not found in buffer!");
|
||||||
LOG_WARNING(RSX, "FP not found in buffer!");
|
vertex_program_type& new_shader = m_vertex_shader_cache[rsx_vp.data];
|
||||||
size_t actualFPSize = ProgramHashUtil::FragmentProgramUtil::getFPBinarySize(vm::base(rsx_fp->addr));
|
backend_traits::recompile_vertex_program(rsx_vp, new_shader, m_next_id++);
|
||||||
void *fpShadowCopy = malloc(actualFPSize);
|
|
||||||
std::memcpy(fpShadowCopy, vm::base(rsx_fp->addr), actualFPSize);
|
|
||||||
typename BackendTraits::FragmentProgramData &newShader = m_cacheFS[fpShadowCopy];
|
|
||||||
BackendTraits::RecompileFragmentProgram(rsx_fp, newShader, m_currentShaderId++);
|
|
||||||
|
|
||||||
return newShader;
|
return std::forward_as_tuple(new_shader, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
typename BackendTraits::VertexProgramData& SearchVp(RSXVertexProgram* rsx_vp, bool &found)
|
/// bool here to inform that the program was preexisting.
|
||||||
|
std::tuple<const fragment_program_type&, bool> search_fragment_program(const RSXFragmentProgram& rsx_fp)
|
||||||
{
|
{
|
||||||
typename binary2VS::iterator It = m_cacheVS.find(rsx_vp->data);
|
const auto& I = m_fragment_shader_cache.find(vm::base(rsx_fp.addr));
|
||||||
if (It != m_cacheVS.end())
|
if (I != m_fragment_shader_cache.end())
|
||||||
{
|
{
|
||||||
found = true;
|
return std::forward_as_tuple(I->second, true);
|
||||||
return It->second;
|
|
||||||
}
|
}
|
||||||
found = false;
|
LOG_NOTICE(RSX, "FP not found in buffer!");
|
||||||
LOG_WARNING(RSX, "VP not found in buffer!");
|
size_t fragment_program_size = program_hash_util::fragment_program_utils::get_fragment_program_ucode_size(vm::base(rsx_fp.addr));
|
||||||
typename BackendTraits::VertexProgramData& newShader = m_cacheVS[rsx_vp->data];
|
gsl::not_null<void*> fragment_program_ucode_copy = malloc(fragment_program_size);
|
||||||
BackendTraits::RecompileVertexProgram(rsx_vp, newShader, m_currentShaderId++);
|
std::memcpy(fragment_program_ucode_copy, vm::base(rsx_fp.addr), fragment_program_size);
|
||||||
|
fragment_program_type &new_shader = m_fragment_shader_cache[fragment_program_ucode_copy];
|
||||||
|
backend_traits::recompile_fragment_program(rsx_fp, new_shader, m_next_id++);
|
||||||
|
|
||||||
return newShader;
|
return std::forward_as_tuple(new_shader, false);
|
||||||
}
|
|
||||||
|
|
||||||
typename BackendTraits::PipelineData *GetProg(const PSOKey &psoKey) const
|
|
||||||
{
|
|
||||||
typename std::unordered_map<PSOKey, typename BackendTraits::PipelineData *, PSOKeyHash, PSOKeyCompare>::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:
|
public:
|
||||||
ProgramStateCache() : m_currentShaderId(0) {}
|
program_state_cache() = default;
|
||||||
~ProgramStateCache()
|
~program_state_cache() = default;
|
||||||
|
|
||||||
|
const vertex_program_type& get_transform_program(const RSXVertexProgram& rsx_vp) const
|
||||||
{
|
{
|
||||||
clear();
|
auto I = m_vertex_shader_cache.find(rsx_vp.data);
|
||||||
|
if (I == m_vertex_shader_cache.end())
|
||||||
|
return I->second;
|
||||||
|
throw new EXCEPTION("Trying to get unknow transform program");
|
||||||
}
|
}
|
||||||
|
|
||||||
const typename BackendTraits::VertexProgramData* get_transform_program(const RSXVertexProgram& rsx_vp) const
|
const fragment_program_type& get_shader_program(const RSXFragmentProgram& rsx_fp) const
|
||||||
{
|
{
|
||||||
typename binary2VS::const_iterator It = m_cacheVS.find(rsx_vp.data);
|
auto I = m_fragment_shader_cache.find(vm::base(rsx_fp.addr));
|
||||||
if (It == m_cacheVS.end())
|
if (I != m_fragment_shader_cache.end())
|
||||||
return nullptr;
|
return I->second;
|
||||||
return &It->second;
|
throw new EXCEPTION("Trying to get unknow shader program");
|
||||||
}
|
}
|
||||||
|
|
||||||
const typename BackendTraits::FragmentProgramData* get_shader_program(const RSXFragmentProgram& rsx_fp) const
|
template<typename... Args>
|
||||||
{
|
pipeline_storage_type& getGraphicPipelineState(
|
||||||
typename binary2FS::const_iterator It = m_cacheFS.find(vm::base(rsx_fp.addr));
|
const RSXVertexProgram& vertexShader,
|
||||||
if (It == m_cacheFS.end())
|
const RSXFragmentProgram& fragmentShader,
|
||||||
return nullptr;
|
const pipeline_properties& pipelineProperties,
|
||||||
return &It->second;
|
Args&& ...args
|
||||||
}
|
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
for (auto pair : m_cachePSO)
|
|
||||||
BackendTraits::DeleteProgram(pair.second);
|
|
||||||
m_cachePSO.clear();
|
|
||||||
|
|
||||||
for (auto pair : m_cacheFS)
|
|
||||||
free(pair.first);
|
|
||||||
|
|
||||||
m_cacheFS.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
typename BackendTraits::PipelineData *getGraphicPipelineState(
|
|
||||||
RSXVertexProgram *vertexShader,
|
|
||||||
RSXFragmentProgram *fragmentShader,
|
|
||||||
const typename BackendTraits::PipelineProperties &pipelineProperties,
|
|
||||||
const typename BackendTraits::ExtraData& extraData
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
typename BackendTraits::PipelineData *result = nullptr;
|
// TODO : use tie and implicit variable declaration syntax with c++17
|
||||||
bool fpFound, vpFound;
|
const auto &vp_search = search_vertex_program(vertexShader);
|
||||||
typename BackendTraits::VertexProgramData &vertexProg = SearchVp(vertexShader, vpFound);
|
const auto &fp_search = search_fragment_program(fragmentShader);
|
||||||
typename BackendTraits::FragmentProgramData &fragmentProg = SearchFp(fragmentShader, fpFound);
|
const vertex_program_type &vertex_program = std::get<0>(vp_search);
|
||||||
|
const fragment_program_type &fragment_program = std::get<0>(fp_search);
|
||||||
|
bool already_existing_fragment_program = std::get<1>(fp_search);
|
||||||
|
bool already_existing_vertex_program = std::get<1>(vp_search);
|
||||||
|
|
||||||
if (fpFound && vpFound)
|
pipeline_key key = { vertex_program.id, fragment_program.id, pipelineProperties };
|
||||||
|
|
||||||
|
if (already_existing_fragment_program && already_existing_vertex_program)
|
||||||
{
|
{
|
||||||
result = GetProg({ vertexProg.id, fragmentProg.id, pipelineProperties });
|
const auto I = m_storage.find(key);
|
||||||
|
if (I != m_storage.end())
|
||||||
|
return I->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result != nullptr)
|
LOG_NOTICE(RSX, "Add program :");
|
||||||
return result;
|
LOG_NOTICE(RSX, "*** vp id = %d", vertex_program.id);
|
||||||
else
|
LOG_NOTICE(RSX, "*** fp id = %d", fragment_program.id);
|
||||||
{
|
|
||||||
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);
|
m_storage[key] = backend_traits::build_pipeline(vertex_program, fragment_program, pipelineProperties, std::forward<Args>(args)...);
|
||||||
Add(result, { vertexProg.id, fragmentProg.id, pipelineProperties });
|
return m_storage[key];
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t get_fragment_constants_buffer_size(const RSXFragmentProgram *fragmentShader) const
|
size_t get_fragment_constants_buffer_size(const RSXFragmentProgram &fragmentShader) const
|
||||||
{
|
{
|
||||||
typename binary2FS::const_iterator It = m_cacheFS.find(vm::base(fragmentShader->addr));
|
const auto I = m_fragment_shader_cache.find(vm::base(fragmentShader.addr));
|
||||||
if (It != m_cacheFS.end())
|
if (I != m_fragment_shader_cache.end())
|
||||||
return It->second.FragmentConstantOffsetCache.size() * 4 * sizeof(float);
|
return I->second.FragmentConstantOffsetCache.size() * 4 * sizeof(float);
|
||||||
LOG_ERROR(RSX, "Can't retrieve constant offset cache");
|
LOG_ERROR(RSX, "Can't retrieve constant offset cache");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fill_fragment_constans_buffer(void *buffer, const RSXFragmentProgram *fragment_program) const
|
void fill_fragment_constans_buffer(gsl::span<f32, gsl::dynamic_range> dst_buffer, const RSXFragmentProgram &fragment_program) const
|
||||||
{
|
{
|
||||||
typename binary2FS::const_iterator It = m_cacheFS.find(vm::base(fragment_program->addr));
|
const auto I = m_fragment_shader_cache.find(vm::base(fragment_program.addr));
|
||||||
if (It == m_cacheFS.end())
|
if (I == m_fragment_shader_cache.end())
|
||||||
return;
|
return;
|
||||||
__m128i mask = _mm_set_epi8(0xE, 0xF, 0xC, 0xD,
|
__m128i mask = _mm_set_epi8(0xE, 0xF, 0xC, 0xD,
|
||||||
0xA, 0xB, 0x8, 0x9,
|
0xA, 0xB, 0x8, 0x9,
|
||||||
0x6, 0x7, 0x4, 0x5,
|
0x6, 0x7, 0x4, 0x5,
|
||||||
0x2, 0x3, 0x0, 0x1);
|
0x2, 0x3, 0x0, 0x1);
|
||||||
|
|
||||||
|
Expects(dst_buffer.size_bytes() >= gsl::narrow<int>(I->second.FragmentConstantOffsetCache.size()) * 16);
|
||||||
|
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
for (size_t offset_in_fragment_program : It->second.FragmentConstantOffsetCache)
|
for (size_t offset_in_fragment_program : I->second.FragmentConstantOffsetCache)
|
||||||
{
|
{
|
||||||
void *data = vm::base(fragment_program->addr + (u32)offset_in_fragment_program);
|
void *data = vm::base(fragment_program.addr + (u32)offset_in_fragment_program);
|
||||||
const __m128i &vector = _mm_loadu_si128((__m128i*)data);
|
const __m128i &vector = _mm_loadu_si128((__m128i*)data);
|
||||||
const __m128i &shuffled_vector = _mm_shuffle_epi8(vector, mask);
|
const __m128i &shuffled_vector = _mm_shuffle_epi8(vector, mask);
|
||||||
_mm_stream_si128((__m128i*)((char*)buffer + offset), shuffled_vector);
|
_mm_stream_si128((__m128i*)dst_buffer.subspan(offset, 4).data(), shuffled_vector);
|
||||||
offset += 4 * sizeof(u32);
|
offset += sizeof(f32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -435,8 +435,8 @@ std::string VertexProgramDecompiler::BuildCode()
|
|||||||
return OS.str();
|
return OS.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
VertexProgramDecompiler::VertexProgramDecompiler(std::vector<u32>& data) :
|
VertexProgramDecompiler::VertexProgramDecompiler(const RSXVertexProgram& prog) :
|
||||||
m_data(data)
|
m_data(prog.data)
|
||||||
{
|
{
|
||||||
m_funcs.emplace_back();
|
m_funcs.emplace_back();
|
||||||
m_funcs[0].offset = 0;
|
m_funcs[0].offset = 0;
|
||||||
|
@ -57,7 +57,7 @@ struct VertexProgramDecompiler
|
|||||||
|
|
||||||
//wxString main;
|
//wxString main;
|
||||||
|
|
||||||
std::vector<u32>& m_data;
|
const std::vector<u32>& m_data;
|
||||||
ParamArray m_parr;
|
ParamArray m_parr;
|
||||||
|
|
||||||
std::string GetMask(bool is_sca);
|
std::string GetMask(bool is_sca);
|
||||||
@ -124,6 +124,6 @@ protected:
|
|||||||
*/
|
*/
|
||||||
virtual void insertMainEnd(std::stringstream &OS) = 0;
|
virtual void insertMainEnd(std::stringstream &OS) = 0;
|
||||||
public:
|
public:
|
||||||
VertexProgramDecompiler(std::vector<u32>& data);
|
VertexProgramDecompiler(const RSXVertexProgram& prog);
|
||||||
std::string Decompile();
|
std::string Decompile();
|
||||||
};
|
};
|
@ -206,7 +206,7 @@ void D3D12GSRender::upload_and_bind_vertex_shader_constants(size_t descriptor_in
|
|||||||
void D3D12GSRender::upload_and_bind_fragment_shader_constants(size_t descriptor_index)
|
void D3D12GSRender::upload_and_bind_fragment_shader_constants(size_t descriptor_index)
|
||||||
{
|
{
|
||||||
// Get constant from fragment program
|
// Get constant from fragment program
|
||||||
size_t buffer_size = m_pso_cache.get_fragment_constants_buffer_size(&fragment_program);
|
size_t buffer_size = m_pso_cache.get_fragment_constants_buffer_size(fragment_program);
|
||||||
// Multiple of 256 never 0
|
// Multiple of 256 never 0
|
||||||
buffer_size = (buffer_size + 255) & ~255;
|
buffer_size = (buffer_size + 255) & ~255;
|
||||||
|
|
||||||
@ -216,7 +216,8 @@ void D3D12GSRender::upload_and_bind_fragment_shader_constants(size_t descriptor_
|
|||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
void *mapped_buffer;
|
void *mapped_buffer;
|
||||||
CHECK_HRESULT(m_constants_data.m_heap->Map(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size), &mapped_buffer));
|
CHECK_HRESULT(m_constants_data.m_heap->Map(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size), &mapped_buffer));
|
||||||
m_pso_cache.fill_fragment_constans_buffer((char*)mapped_buffer + heap_offset, &fragment_program);
|
float *buffer = (float*)((char*)mapped_buffer + heap_offset);
|
||||||
|
m_pso_cache.fill_fragment_constans_buffer({ buffer, gsl::narrow<int>(buffer_size) }, fragment_program);
|
||||||
m_constants_data.m_heap->Unmap(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
m_constants_data.m_heap->Unmap(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||||
|
|
||||||
D3D12_CONSTANT_BUFFER_VIEW_DESC constant_buffer_view_desc = {
|
D3D12_CONSTANT_BUFFER_VIEW_DESC constant_buffer_view_desc = {
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
#include "Emu/Memory/Memory.h"
|
#include "Emu/Memory/Memory.h"
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
|
|
||||||
D3D12FragmentDecompiler::D3D12FragmentDecompiler(u32 addr, u32& size, u32 ctrl, const std::vector<texture_dimension> &texture_dimensions) :
|
D3D12FragmentDecompiler::D3D12FragmentDecompiler(const RSXFragmentProgram &prog, u32& size) :
|
||||||
FragmentProgramDecompiler(addr, size, ctrl, texture_dimensions)
|
FragmentProgramDecompiler(prog, size)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -20,5 +20,5 @@ protected:
|
|||||||
virtual void insertMainStart(std::stringstream &OS) override;
|
virtual void insertMainStart(std::stringstream &OS) override;
|
||||||
virtual void insertMainEnd(std::stringstream &OS) override;
|
virtual void insertMainEnd(std::stringstream &OS) override;
|
||||||
public:
|
public:
|
||||||
D3D12FragmentDecompiler(u32 addr, u32& size, u32 ctrl, const std::vector<texture_dimension> &texture_dimensions);
|
D3D12FragmentDecompiler(const RSXFragmentProgram &prog, u32& size);
|
||||||
};
|
};
|
||||||
|
@ -87,7 +87,7 @@ D3D12DLLManagement::~D3D12DLLManagement()
|
|||||||
}
|
}
|
||||||
|
|
||||||
D3D12GSRender::D3D12GSRender()
|
D3D12GSRender::D3D12GSRender()
|
||||||
: GSRender(frame_type::DX12), m_d3d12_lib(), m_current_pso(nullptr)
|
: GSRender(frame_type::DX12), m_d3d12_lib(), m_current_pso({})
|
||||||
{
|
{
|
||||||
m_previous_address_a = 0;
|
m_previous_address_a = 0;
|
||||||
m_previous_address_b = 0;
|
m_previous_address_b = 0;
|
||||||
@ -277,7 +277,7 @@ void D3D12GSRender::end()
|
|||||||
std::chrono::time_point<std::chrono::system_clock> program_load_end = std::chrono::system_clock::now();
|
std::chrono::time_point<std::chrono::system_clock> program_load_end = std::chrono::system_clock::now();
|
||||||
m_timers.m_program_load_duration += std::chrono::duration_cast<std::chrono::microseconds>(program_load_end - program_load_start).count();
|
m_timers.m_program_load_duration += std::chrono::duration_cast<std::chrono::microseconds>(program_load_end - program_load_start).count();
|
||||||
|
|
||||||
get_current_resource_storage().command_list->SetGraphicsRootSignature(m_root_signatures[std::get<2>(*m_current_pso)].Get());
|
get_current_resource_storage().command_list->SetGraphicsRootSignature(m_root_signatures[std::get<2>(m_current_pso)].Get());
|
||||||
get_current_resource_storage().command_list->OMSetStencilRef(rsx::method_registers[NV4097_SET_STENCIL_FUNC_REF]);
|
get_current_resource_storage().command_list->OMSetStencilRef(rsx::method_registers[NV4097_SET_STENCIL_FUNC_REF]);
|
||||||
|
|
||||||
std::chrono::time_point<std::chrono::system_clock> constants_duration_start = std::chrono::system_clock::now();
|
std::chrono::time_point<std::chrono::system_clock> constants_duration_start = std::chrono::system_clock::now();
|
||||||
@ -291,12 +291,12 @@ void D3D12GSRender::end()
|
|||||||
std::chrono::time_point<std::chrono::system_clock> constants_duration_end = std::chrono::system_clock::now();
|
std::chrono::time_point<std::chrono::system_clock> constants_duration_end = std::chrono::system_clock::now();
|
||||||
m_timers.m_constants_duration += std::chrono::duration_cast<std::chrono::microseconds>(constants_duration_end - constants_duration_start).count();
|
m_timers.m_constants_duration += std::chrono::duration_cast<std::chrono::microseconds>(constants_duration_end - constants_duration_start).count();
|
||||||
|
|
||||||
get_current_resource_storage().command_list->SetPipelineState(std::get<0>(*m_current_pso));
|
get_current_resource_storage().command_list->SetPipelineState(std::get<0>(m_current_pso).Get());
|
||||||
|
|
||||||
std::chrono::time_point<std::chrono::system_clock> texture_duration_start = std::chrono::system_clock::now();
|
std::chrono::time_point<std::chrono::system_clock> texture_duration_start = std::chrono::system_clock::now();
|
||||||
if (std::get<2>(*m_current_pso) > 0)
|
if (std::get<2>(m_current_pso) > 0)
|
||||||
{
|
{
|
||||||
upload_and_bind_textures(get_current_resource_storage().command_list.Get(), currentDescriptorIndex + 3, std::get<2>(*m_current_pso) > 0);
|
upload_and_bind_textures(get_current_resource_storage().command_list.Get(), currentDescriptorIndex + 3, std::get<2>(m_current_pso) > 0);
|
||||||
|
|
||||||
|
|
||||||
get_current_resource_storage().command_list->SetGraphicsRootDescriptorTable(0,
|
get_current_resource_storage().command_list->SetGraphicsRootDescriptorTable(0,
|
||||||
@ -308,8 +308,8 @@ void D3D12GSRender::end()
|
|||||||
.Offset((INT)get_current_resource_storage().current_sampler_index, g_descriptor_stride_samplers)
|
.Offset((INT)get_current_resource_storage().current_sampler_index, g_descriptor_stride_samplers)
|
||||||
);
|
);
|
||||||
|
|
||||||
get_current_resource_storage().current_sampler_index += std::get<2>(*m_current_pso);
|
get_current_resource_storage().current_sampler_index += std::get<2>(m_current_pso);
|
||||||
get_current_resource_storage().descriptors_heap_index += std::get<2>(*m_current_pso) + 3;
|
get_current_resource_storage().descriptors_heap_index += std::get<2>(m_current_pso) + 3;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -67,7 +67,7 @@ private:
|
|||||||
RSXVertexProgram vertex_program;
|
RSXVertexProgram vertex_program;
|
||||||
RSXFragmentProgram fragment_program;
|
RSXFragmentProgram fragment_program;
|
||||||
PipelineStateObjectCache m_pso_cache;
|
PipelineStateObjectCache m_pso_cache;
|
||||||
std::tuple<ID3D12PipelineState *, std::vector<size_t>, size_t> *m_current_pso;
|
std::tuple<ComPtr<ID3D12PipelineState>, std::vector<size_t>, size_t> m_current_pso;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
@ -146,7 +146,7 @@ private:
|
|||||||
void init_d2d_structures();
|
void init_d2d_structures();
|
||||||
void release_d2d_structures();
|
void release_d2d_structures();
|
||||||
|
|
||||||
bool load_program();
|
void load_program();
|
||||||
|
|
||||||
void set_rtt_and_ds(ID3D12GraphicsCommandList *command_list);
|
void set_rtt_and_ds(ID3D12GraphicsCommandList *command_list);
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ void Shader::Compile(const std::string &code, SHADER_TYPE st)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool D3D12GSRender::load_program()
|
void D3D12GSRender::load_program()
|
||||||
{
|
{
|
||||||
u32 transform_program_start = rsx::method_registers[NV4097_SET_TRANSFORM_PROGRAM_START];
|
u32 transform_program_start = rsx::method_registers[NV4097_SET_TRANSFORM_PROGRAM_START];
|
||||||
vertex_program.data.reserve((512 - transform_program_start) * 4);
|
vertex_program.data.reserve((512 - transform_program_start) * 4);
|
||||||
@ -256,12 +256,12 @@ bool D3D12GSRender::load_program()
|
|||||||
prop.CutValue = ((rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4) == CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32) ?
|
prop.CutValue = ((rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4) == CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32) ?
|
||||||
D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF : D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF;
|
D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF : D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF;
|
||||||
|
|
||||||
m_current_pso = m_pso_cache.getGraphicPipelineState(&vertex_program, &fragment_program, prop, std::make_pair(m_device.Get(), m_root_signatures));
|
m_current_pso = m_pso_cache.getGraphicPipelineState(vertex_program, fragment_program, prop, m_device.Get(), m_root_signatures);
|
||||||
return m_current_pso != nullptr;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<std::string, std::string> D3D12GSRender::get_programs() const
|
std::pair<std::string, std::string> D3D12GSRender::get_programs() const
|
||||||
{
|
{
|
||||||
return std::make_pair(m_pso_cache.get_transform_program(vertex_program)->content, m_pso_cache.get_shader_program(fragment_program)->content);
|
return std::make_pair(m_pso_cache.get_transform_program(vertex_program).content, m_pso_cache.get_shader_program(fragment_program).content);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -85,8 +85,9 @@ public:
|
|||||||
SHADER_TYPE_FRAGMENT
|
SHADER_TYPE_FRAGMENT
|
||||||
};
|
};
|
||||||
|
|
||||||
Shader() : bytecode(nullptr) {}
|
Shader() = default;
|
||||||
~Shader() {}
|
~Shader() = default;
|
||||||
|
Shader(const Shader &) = delete;
|
||||||
|
|
||||||
u32 id;
|
u32 id;
|
||||||
ComPtr<ID3DBlob> bytecode;
|
ComPtr<ID3DBlob> bytecode;
|
||||||
@ -137,16 +138,16 @@ std::vector<D3D12_INPUT_ELEMENT_DESC> completes_IA_desc(const std::vector<D3D12_
|
|||||||
|
|
||||||
struct D3D12Traits
|
struct D3D12Traits
|
||||||
{
|
{
|
||||||
typedef Shader VertexProgramData;
|
using vertex_program_type = Shader;
|
||||||
typedef Shader FragmentProgramData;
|
using fragment_program_type = Shader;
|
||||||
typedef std::tuple<ID3D12PipelineState *, std::vector<size_t>, size_t> PipelineData;
|
using pipeline_storage_type = std::tuple<ComPtr<ID3D12PipelineState>, std::vector<size_t>, size_t>;
|
||||||
typedef D3D12PipelineProperties PipelineProperties;
|
using pipeline_properties = D3D12PipelineProperties;
|
||||||
typedef std::pair<ID3D12Device *, ComPtr<ID3D12RootSignature> *> ExtraData;
|
|
||||||
|
|
||||||
static
|
static
|
||||||
void RecompileFragmentProgram(RSXFragmentProgram *RSXFP, FragmentProgramData& fragmentProgramData, size_t ID)
|
void recompile_fragment_program(const RSXFragmentProgram &RSXFP, fragment_program_type& fragmentProgramData, size_t ID)
|
||||||
{
|
{
|
||||||
D3D12FragmentDecompiler FS(RSXFP->addr, RSXFP->size, RSXFP->ctrl, RSXFP->texture_dimensions);
|
u32 size;
|
||||||
|
D3D12FragmentDecompiler FS(RSXFP, size);
|
||||||
const std::string &shader = FS.Decompile();
|
const std::string &shader = FS.Decompile();
|
||||||
fragmentProgramData.Compile(shader, Shader::SHADER_TYPE::SHADER_TYPE_FRAGMENT);
|
fragmentProgramData.Compile(shader, Shader::SHADER_TYPE::SHADER_TYPE_FRAGMENT);
|
||||||
fragmentProgramData.m_textureCount = 0;
|
fragmentProgramData.m_textureCount = 0;
|
||||||
@ -170,9 +171,9 @@ struct D3D12Traits
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void RecompileVertexProgram(RSXVertexProgram *RSXVP, VertexProgramData& vertexProgramData, size_t ID)
|
void recompile_vertex_program(const RSXVertexProgram &RSXVP, vertex_program_type& vertexProgramData, size_t ID)
|
||||||
{
|
{
|
||||||
D3D12VertexProgramDecompiler VS(RSXVP->data);
|
D3D12VertexProgramDecompiler VS(RSXVP);
|
||||||
std::string shaderCode = VS.Decompile();
|
std::string shaderCode = VS.Decompile();
|
||||||
vertexProgramData.Compile(shaderCode, Shader::SHADER_TYPE::SHADER_TYPE_VERTEX);
|
vertexProgramData.Compile(shaderCode, Shader::SHADER_TYPE::SHADER_TYPE_VERTEX);
|
||||||
vertexProgramData.vertex_shader_inputs = VS.input_slots;
|
vertexProgramData.vertex_shader_inputs = VS.input_slots;
|
||||||
@ -181,24 +182,24 @@ struct D3D12Traits
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
PipelineData *BuildProgram(VertexProgramData &vertexProgramData, FragmentProgramData &fragmentProgramData, const PipelineProperties &pipelineProperties, const ExtraData& extraData)
|
pipeline_storage_type build_pipeline(
|
||||||
|
const vertex_program_type &vertexProgramData, const fragment_program_type &fragmentProgramData, const pipeline_properties &pipelineProperties,
|
||||||
|
ID3D12Device *device, gsl::span<ComPtr<ID3D12RootSignature>, 17> root_signatures)
|
||||||
{
|
{
|
||||||
|
std::tuple<ID3D12PipelineState *, std::vector<size_t>, size_t> result = {};
|
||||||
std::tuple<ID3D12PipelineState *, std::vector<size_t>, size_t> *result = new std::tuple<ID3D12PipelineState *, std::vector<size_t>, size_t>();
|
|
||||||
D3D12_GRAPHICS_PIPELINE_STATE_DESC graphicPipelineStateDesc = {};
|
D3D12_GRAPHICS_PIPELINE_STATE_DESC graphicPipelineStateDesc = {};
|
||||||
|
|
||||||
if (vertexProgramData.bytecode == nullptr)
|
if (vertexProgramData.bytecode == nullptr)
|
||||||
return nullptr;
|
throw new EXCEPTION("Vertex program compilation failure");
|
||||||
graphicPipelineStateDesc.VS.BytecodeLength = vertexProgramData.bytecode->GetBufferSize();
|
graphicPipelineStateDesc.VS.BytecodeLength = vertexProgramData.bytecode->GetBufferSize();
|
||||||
graphicPipelineStateDesc.VS.pShaderBytecode = vertexProgramData.bytecode->GetBufferPointer();
|
graphicPipelineStateDesc.VS.pShaderBytecode = vertexProgramData.bytecode->GetBufferPointer();
|
||||||
|
|
||||||
if (fragmentProgramData.bytecode == nullptr)
|
if (fragmentProgramData.bytecode == nullptr)
|
||||||
return nullptr;
|
throw new EXCEPTION("fragment program compilation failure");
|
||||||
graphicPipelineStateDesc.PS.BytecodeLength = fragmentProgramData.bytecode->GetBufferSize();
|
graphicPipelineStateDesc.PS.BytecodeLength = fragmentProgramData.bytecode->GetBufferSize();
|
||||||
graphicPipelineStateDesc.PS.pShaderBytecode = fragmentProgramData.bytecode->GetBufferPointer();
|
graphicPipelineStateDesc.PS.pShaderBytecode = fragmentProgramData.bytecode->GetBufferPointer();
|
||||||
|
|
||||||
graphicPipelineStateDesc.pRootSignature = extraData.second[fragmentProgramData.m_textureCount].Get();
|
graphicPipelineStateDesc.pRootSignature = root_signatures[fragmentProgramData.m_textureCount].Get();
|
||||||
std::get<2>(*result) = fragmentProgramData.m_textureCount;
|
|
||||||
|
|
||||||
graphicPipelineStateDesc.BlendState = pipelineProperties.Blend;
|
graphicPipelineStateDesc.BlendState = pipelineProperties.Blend;
|
||||||
graphicPipelineStateDesc.DepthStencilState = pipelineProperties.DepthStencil;
|
graphicPipelineStateDesc.DepthStencilState = pipelineProperties.DepthStencil;
|
||||||
@ -220,22 +221,15 @@ struct D3D12Traits
|
|||||||
|
|
||||||
graphicPipelineStateDesc.IBStripCutValue = pipelineProperties.CutValue;
|
graphicPipelineStateDesc.IBStripCutValue = pipelineProperties.CutValue;
|
||||||
|
|
||||||
CHECK_HRESULT(extraData.first->CreateGraphicsPipelineState(&graphicPipelineStateDesc, IID_PPV_ARGS(&std::get<0>(*result))));
|
ComPtr<ID3D12PipelineState> pso;
|
||||||
std::get<1>(*result) = vertexProgramData.vertex_shader_inputs;
|
CHECK_HRESULT(device->CreateGraphicsPipelineState(&graphicPipelineStateDesc, IID_PPV_ARGS(pso.GetAddressOf())));
|
||||||
|
|
||||||
std::wstring name = L"PSO_" + std::to_wstring(vertexProgramData.id) + L"_" + std::to_wstring(fragmentProgramData.id);
|
std::wstring name = L"PSO_" + std::to_wstring(vertexProgramData.id) + L"_" + std::to_wstring(fragmentProgramData.id);
|
||||||
std::get<0>(*result)->SetName(name.c_str());
|
pso->SetName(name.c_str());
|
||||||
return result;
|
return std::make_tuple(pso, vertexProgramData.vertex_shader_inputs, fragmentProgramData.m_textureCount);
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
void DeleteProgram(PipelineData *ptr)
|
|
||||||
{
|
|
||||||
std::get<0>(*ptr)->Release();
|
|
||||||
delete ptr;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class PipelineStateObjectCache : public ProgramStateCache<D3D12Traits>
|
class PipelineStateObjectCache : public program_state_cache<D3D12Traits>
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
@ -181,8 +181,8 @@ void D3D12VertexProgramDecompiler::insertMainEnd(std::stringstream & OS)
|
|||||||
OS << "}" << std::endl;
|
OS << "}" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
D3D12VertexProgramDecompiler::D3D12VertexProgramDecompiler(std::vector<u32>& data) :
|
D3D12VertexProgramDecompiler::D3D12VertexProgramDecompiler(const RSXVertexProgram &prog) :
|
||||||
VertexProgramDecompiler(data)
|
VertexProgramDecompiler(prog)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -20,5 +20,5 @@ protected:
|
|||||||
virtual void insertMainEnd(std::stringstream &OS);
|
virtual void insertMainEnd(std::stringstream &OS);
|
||||||
public:
|
public:
|
||||||
std::vector<size_t> input_slots;
|
std::vector<size_t> input_slots;
|
||||||
D3D12VertexProgramDecompiler(std::vector<u32>& data);
|
D3D12VertexProgramDecompiler(const RSXVertexProgram &prog);
|
||||||
};
|
};
|
||||||
|
@ -172,9 +172,10 @@ GLFragmentProgram::~GLFragmentProgram()
|
|||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
|
|
||||||
void GLFragmentProgram::Decompile(RSXFragmentProgram& prog, const std::vector<texture_dimension> &td)
|
void GLFragmentProgram::Decompile(const RSXFragmentProgram& prog)
|
||||||
{
|
{
|
||||||
GLFragmentDecompilerThread decompiler(shader, parr, prog.addr, prog.size, prog.ctrl, td);
|
u32 size;
|
||||||
|
GLFragmentDecompilerThread decompiler(shader, parr, prog, size);
|
||||||
decompiler.Task();
|
decompiler.Task();
|
||||||
for (const ParamType& PT : decompiler.m_parr.params[PF_PARAM_UNIFORM])
|
for (const ParamType& PT : decompiler.m_parr.params[PF_PARAM_UNIFORM])
|
||||||
{
|
{
|
||||||
|
@ -9,8 +9,8 @@ struct GLFragmentDecompilerThread : public FragmentProgramDecompiler
|
|||||||
std::string& m_shader;
|
std::string& m_shader;
|
||||||
ParamArray& m_parrDummy;
|
ParamArray& m_parrDummy;
|
||||||
public:
|
public:
|
||||||
GLFragmentDecompilerThread(std::string& shader, ParamArray& parr, u32 addr, u32& size, u32 ctrl, const std::vector<texture_dimension> &texture_dimensions)
|
GLFragmentDecompilerThread(std::string& shader, ParamArray& parr, const RSXFragmentProgram &prog, u32& size)
|
||||||
: FragmentProgramDecompiler(addr, size, ctrl, texture_dimensions)
|
: FragmentProgramDecompiler(prog, size)
|
||||||
, m_shader(shader)
|
, m_shader(shader)
|
||||||
, m_parrDummy(parr)
|
, m_parrDummy(parr)
|
||||||
{
|
{
|
||||||
@ -51,7 +51,7 @@ public:
|
|||||||
* @param prog RSXShaderProgram specifying the location and size of the shader in memory
|
* @param prog RSXShaderProgram specifying the location and size of the shader in memory
|
||||||
* @param td texture dimensions of input textures
|
* @param td texture dimensions of input textures
|
||||||
*/
|
*/
|
||||||
void Decompile(RSXFragmentProgram& prog, const std::vector<texture_dimension> &td);
|
void Decompile(const RSXFragmentProgram& prog);
|
||||||
|
|
||||||
/** Compile the decompiled fragment shader into a format we can use with OpenGL. */
|
/** Compile the decompiled fragment shader into a format we can use with OpenGL. */
|
||||||
void Compile();
|
void Compile();
|
||||||
|
@ -576,8 +576,6 @@ void GLGSRender::on_exit()
|
|||||||
|
|
||||||
if (m_fragment_constants_buffer)
|
if (m_fragment_constants_buffer)
|
||||||
m_fragment_constants_buffer.remove();
|
m_fragment_constants_buffer.remove();
|
||||||
|
|
||||||
m_prog_buffer.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void nv4097_clear_surface(u32 arg, GLGSRender* renderer)
|
void nv4097_clear_surface(u32 arg, GLGSRender* renderer)
|
||||||
@ -698,7 +696,7 @@ bool GLGSRender::load_program()
|
|||||||
fragment_program.texture_dimensions.push_back(texture_dimension::texture_dimension_2d);
|
fragment_program.texture_dimensions.push_back(texture_dimension::texture_dimension_2d);
|
||||||
}
|
}
|
||||||
|
|
||||||
__glcheck m_program = m_prog_buffer.getGraphicPipelineState(&vertex_program, &fragment_program, nullptr, nullptr);
|
__glcheck m_program = &m_prog_buffer.getGraphicPipelineState(vertex_program, fragment_program, nullptr);
|
||||||
__glcheck m_program->use();
|
__glcheck m_program->use();
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@ -750,10 +748,10 @@ bool GLGSRender::load_program()
|
|||||||
glUnmapBuffer(GL_UNIFORM_BUFFER);
|
glUnmapBuffer(GL_UNIFORM_BUFFER);
|
||||||
|
|
||||||
glBindBuffer(GL_UNIFORM_BUFFER, m_fragment_constants_buffer.id());
|
glBindBuffer(GL_UNIFORM_BUFFER, m_fragment_constants_buffer.id());
|
||||||
size_t buffer_size = m_prog_buffer.get_fragment_constants_buffer_size(&fragment_program);
|
size_t buffer_size = m_prog_buffer.get_fragment_constants_buffer_size(fragment_program);
|
||||||
glBufferData(GL_UNIFORM_BUFFER, buffer_size, nullptr, GL_STATIC_DRAW);
|
glBufferData(GL_UNIFORM_BUFFER, buffer_size, nullptr, GL_STATIC_DRAW);
|
||||||
buffer = glMapBuffer(GL_UNIFORM_BUFFER, GL_WRITE_ONLY);
|
buffer = glMapBuffer(GL_UNIFORM_BUFFER, GL_WRITE_ONLY);
|
||||||
m_prog_buffer.fill_fragment_constans_buffer(buffer, &fragment_program);
|
m_prog_buffer.fill_fragment_constans_buffer({ static_cast<float*>(buffer), gsl::narrow<int>(buffer_size) }, fragment_program);
|
||||||
glUnmapBuffer(GL_UNIFORM_BUFFER);
|
glUnmapBuffer(GL_UNIFORM_BUFFER);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -5,16 +5,15 @@
|
|||||||
|
|
||||||
struct GLTraits
|
struct GLTraits
|
||||||
{
|
{
|
||||||
typedef GLVertexProgram VertexProgramData;
|
using vertex_program_type = GLVertexProgram;
|
||||||
typedef GLFragmentProgram FragmentProgramData;
|
using fragment_program_type = GLFragmentProgram;
|
||||||
typedef gl::glsl::program PipelineData;
|
using pipeline_storage_type = gl::glsl::program;
|
||||||
typedef void* PipelineProperties;
|
using pipeline_properties = void*;
|
||||||
typedef void* ExtraData;
|
|
||||||
|
|
||||||
static
|
static
|
||||||
void RecompileFragmentProgram(RSXFragmentProgram *RSXFP, FragmentProgramData& fragmentProgramData, size_t ID)
|
void recompile_fragment_program(const RSXFragmentProgram &RSXFP, fragment_program_type& fragmentProgramData, size_t ID)
|
||||||
{
|
{
|
||||||
fragmentProgramData.Decompile(*RSXFP, RSXFP->texture_dimensions);
|
fragmentProgramData.Decompile(RSXFP);
|
||||||
fragmentProgramData.Compile();
|
fragmentProgramData.Compile();
|
||||||
//checkForGlError("m_fragment_prog.Compile");
|
//checkForGlError("m_fragment_prog.Compile");
|
||||||
|
|
||||||
@ -22,9 +21,9 @@ struct GLTraits
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void RecompileVertexProgram(RSXVertexProgram *RSXVP, VertexProgramData& vertexProgramData, size_t ID)
|
void recompile_vertex_program(const RSXVertexProgram &RSXVP, vertex_program_type& vertexProgramData, size_t ID)
|
||||||
{
|
{
|
||||||
vertexProgramData.Decompile(*RSXVP);
|
vertexProgramData.Decompile(RSXVP);
|
||||||
vertexProgramData.Compile();
|
vertexProgramData.Compile();
|
||||||
//checkForGlError("m_vertex_prog.Compile");
|
//checkForGlError("m_vertex_prog.Compile");
|
||||||
|
|
||||||
@ -32,10 +31,10 @@ struct GLTraits
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
PipelineData *BuildProgram(VertexProgramData &vertexProgramData, FragmentProgramData &fragmentProgramData, const PipelineProperties &pipelineProperties, const ExtraData& extraData)
|
pipeline_storage_type build_pipeline(const vertex_program_type &vertexProgramData, const fragment_program_type &fragmentProgramData, const pipeline_properties &pipelineProperties)
|
||||||
{
|
{
|
||||||
PipelineData *result = new PipelineData();
|
pipeline_storage_type result;
|
||||||
__glcheck result->create()
|
__glcheck result.create()
|
||||||
.attach(gl::glsl::shader_view(vertexProgramData.id))
|
.attach(gl::glsl::shader_view(vertexProgramData.id))
|
||||||
.attach(gl::glsl::shader_view(fragmentProgramData.id))
|
.attach(gl::glsl::shader_view(fragmentProgramData.id))
|
||||||
.bind_fragment_data_location("ocol0", 0)
|
.bind_fragment_data_location("ocol0", 0)
|
||||||
@ -43,9 +42,9 @@ struct GLTraits
|
|||||||
.bind_fragment_data_location("ocol2", 2)
|
.bind_fragment_data_location("ocol2", 2)
|
||||||
.bind_fragment_data_location("ocol3", 3)
|
.bind_fragment_data_location("ocol3", 3)
|
||||||
.make();
|
.make();
|
||||||
__glcheck result->use();
|
__glcheck result.use();
|
||||||
|
|
||||||
LOG_NOTICE(RSX, "*** prog id = %d", result->id());
|
LOG_NOTICE(RSX, "*** prog id = %d", result.id());
|
||||||
LOG_NOTICE(RSX, "*** vp id = %d", vertexProgramData.id);
|
LOG_NOTICE(RSX, "*** vp id = %d", vertexProgramData.id);
|
||||||
LOG_NOTICE(RSX, "*** fp id = %d", fragmentProgramData.id);
|
LOG_NOTICE(RSX, "*** fp id = %d", fragmentProgramData.id);
|
||||||
|
|
||||||
@ -54,14 +53,8 @@ struct GLTraits
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
|
||||||
void DeleteProgram(PipelineData *ptr)
|
|
||||||
{
|
|
||||||
ptr->remove();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class GLProgramBuffer : public ProgramStateCache<GLTraits>
|
class GLProgramBuffer : public program_state_cache<GLTraits>
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
@ -166,9 +166,9 @@ GLVertexProgram::~GLVertexProgram()
|
|||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
|
|
||||||
void GLVertexProgram::Decompile(RSXVertexProgram& prog)
|
void GLVertexProgram::Decompile(const RSXVertexProgram& prog)
|
||||||
{
|
{
|
||||||
GLVertexDecompilerThread decompiler(prog.data, shader, parr);
|
GLVertexDecompilerThread decompiler(prog, shader, parr);
|
||||||
decompiler.Task();
|
decompiler.Task();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,8 +20,8 @@ protected:
|
|||||||
virtual void insertMainStart(std::stringstream &OS) override;
|
virtual void insertMainStart(std::stringstream &OS) override;
|
||||||
virtual void insertMainEnd(std::stringstream &OS) override;
|
virtual void insertMainEnd(std::stringstream &OS) override;
|
||||||
public:
|
public:
|
||||||
GLVertexDecompilerThread(std::vector<u32>& data, std::string& shader, ParamArray& parr)
|
GLVertexDecompilerThread(const RSXVertexProgram &prog, std::string& shader, ParamArray& parr)
|
||||||
: VertexProgramDecompiler(data)
|
: VertexProgramDecompiler(prog)
|
||||||
, m_shader(shader)
|
, m_shader(shader)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -39,7 +39,7 @@ public:
|
|||||||
u32 id = 0;
|
u32 id = 0;
|
||||||
std::string shader;
|
std::string shader;
|
||||||
|
|
||||||
void Decompile(RSXVertexProgram& prog);
|
void Decompile(const RSXVertexProgram& prog);
|
||||||
void Compile();
|
void Compile();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -2148,7 +2148,7 @@ namespace gl
|
|||||||
}
|
}
|
||||||
|
|
||||||
program() = default;
|
program() = default;
|
||||||
program(program&) = delete;
|
program(const program&) = delete;
|
||||||
program(program&& program_)
|
program(program&& program_)
|
||||||
{
|
{
|
||||||
swap(program_);
|
swap(program_);
|
||||||
|
@ -124,6 +124,7 @@
|
|||||||
<ClCompile Include="Emu\RSX\CgBinaryVertexProgram.cpp" />
|
<ClCompile Include="Emu\RSX\CgBinaryVertexProgram.cpp" />
|
||||||
<ClCompile Include="Emu\RSX\Common\BufferUtils.cpp" />
|
<ClCompile Include="Emu\RSX\Common\BufferUtils.cpp" />
|
||||||
<ClCompile Include="Emu\RSX\Common\FragmentProgramDecompiler.cpp" />
|
<ClCompile Include="Emu\RSX\Common\FragmentProgramDecompiler.cpp" />
|
||||||
|
<ClCompile Include="Emu\RSX\Common\ProgramStateCache.cpp" />
|
||||||
<ClCompile Include="Emu\RSX\Common\ShaderParam.cpp" />
|
<ClCompile Include="Emu\RSX\Common\ShaderParam.cpp" />
|
||||||
<ClCompile Include="Emu\RSX\Common\TextureUtils.cpp" />
|
<ClCompile Include="Emu\RSX\Common\TextureUtils.cpp" />
|
||||||
<ClCompile Include="Emu\RSX\Common\VertexProgramDecompiler.cpp" />
|
<ClCompile Include="Emu\RSX\Common\VertexProgramDecompiler.cpp" />
|
||||||
|
@ -933,6 +933,9 @@
|
|||||||
<ClCompile Include="stdafx.cpp">
|
<ClCompile Include="stdafx.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="Emu\RSX\Common\ProgramStateCache.cpp">
|
||||||
|
<Filter>Emu\GPU\RSX\Common</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="Crypto\aes.h">
|
<ClInclude Include="Crypto\aes.h">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user