refactory some render state and shader

This commit is contained in:
Asuka 2022-07-01 02:18:07 +08:00
parent 32277e2d83
commit 747ab5d998
18 changed files with 409 additions and 196 deletions

View file

@ -1,26 +1,17 @@
#include "GcnHeader.h"
#include "GcnConstants.h"
#include "GcnDecoder.h"
#include "GcnProgramInfo.h"
#include "Gnm/GnmConstant.h"
LOG_CHANNEL(Graphic.Gcn.GcnHeader);
using namespace sce::Gnm;
namespace sce::gcn
{
GcnHeader::GcnHeader(const uint8_t* shaderCode)
{
parseHeader(shaderCode);
extractResourceTable(shaderCode);
}
GcnHeader::~GcnHeader()
{
}
void GcnHeader::parseHeader(
const uint8_t* shaderCode)
GcnBinaryInfo::GcnBinaryInfo(const uint8_t* shaderCode)
{
const uint32_t* token = reinterpret_cast<const uint32_t*>(shaderCode);
const uint32_t tokenMovVccHi = 0xBEEB03FF;
@ -31,7 +22,64 @@ namespace sce::gcn
// but if it is, we can still search for the header magic 'OrbShdr'
LOG_ASSERT(token[0] == tokenMovVccHi, "first instruction is not s_mov_b32 vcc_hi, #imm");
const ShaderBinaryInfo* binaryInfo = reinterpret_cast<const ShaderBinaryInfo*>(token + (token[1] + 1) * 2);
m_binInfo = reinterpret_cast<const ShaderBinaryInfo*>(token + (token[1] + 1) * 2);
}
GcnBinaryInfo::~GcnBinaryInfo()
{
}
GcnHeader::GcnHeader(const uint8_t* shaderCode)
{
parseHeader(shaderCode);
extractResourceTable(shaderCode);
}
GcnHeader::~GcnHeader()
{
}
GcnProgramType GcnHeader::type() const
{
GcnProgramType result;
ShaderBinaryType binType = static_cast<ShaderBinaryType>(m_binInfo.m_type);
switch (binType)
{
case ShaderBinaryType::kPixelShader:
result = GcnProgramType::PixelShader;
break;
case ShaderBinaryType::kVertexShader:
result = GcnProgramType::VertexShader;
break;
case ShaderBinaryType::kComputeShader:
result = GcnProgramType::ComputeShader;
break;
case ShaderBinaryType::kGeometryShader:
result = GcnProgramType::GeometryShader;
break;
case ShaderBinaryType::kHullShader:
result = GcnProgramType::HullShader;
break;
case ShaderBinaryType::kDomainShader:
result = GcnProgramType::DomainShader;
break;
case ShaderBinaryType::kLocalShader:
case ShaderBinaryType::kExportShader:
case ShaderBinaryType::kUnknown:
default:
LOG_ASSERT(false, "unknown shader type.");
break;
}
return result;
}
void GcnHeader::parseHeader(
const uint8_t* shaderCode)
{
GcnBinaryInfo info(shaderCode);
const ShaderBinaryInfo* binaryInfo = info.info();
std::memcpy(&m_binInfo, binaryInfo, sizeof(ShaderBinaryInfo));
// Get usage masks and input usage slots
@ -154,4 +202,6 @@ namespace sce::gcn
return result;
}
} // namespace sce::gcn

View file

@ -9,6 +9,8 @@
namespace sce::gcn
{
enum class GcnProgramType;
/**
* \brief Represent a resource bound to a GCN shader
*/
@ -35,6 +37,54 @@ namespace sce::gcn
using GcnShaderResourceTable = std::vector<GcnShaderResource>;
/**
* \brief Light weight binary information parser
*
* Data in this class is not persistent, will become
* invalid when shader code released.
*/
class GcnBinaryInfo
{
public:
GcnBinaryInfo(
const uint8_t* shaderCode);
~GcnBinaryInfo();
/**
* \brief Code length
*
* Gcn instruction code length in bytes.
* Does not include header and
* other meta information
*/
uint32_t length() const
{
return m_binInfo->m_length;
}
/**
* \brief Unique key
*
* Used to identify the shader
*/
GcnShaderKey key() const
{
return GcnShaderKey(
m_binInfo->m_shaderHash0, m_binInfo->m_crc32);
}
/**
* \brief Information of shader binary
*/
const ShaderBinaryInfo* info() const
{
return m_binInfo;
}
private:
const ShaderBinaryInfo* m_binInfo = nullptr;
};
/**
* \brief Header information
@ -54,6 +104,8 @@ namespace sce::gcn
const uint8_t* shaderCode);
~GcnHeader();
GcnProgramType type() const;
/**
* \brief Unique id of the shader
*/
@ -71,11 +123,6 @@ namespace sce::gcn
return m_binInfo.m_length;
}
const ShaderBinaryInfo& getShaderBinaryInfo() const
{
return m_binInfo;
}
const InputUsageSlotTable& getInputUsageSlotTable() const
{
return m_inputUsageSlotTable;

View file

@ -16,11 +16,9 @@ LOG_CHANNEL(Graphic.Gcn.GcnModule);
namespace sce::gcn
{
GcnModule::GcnModule(
GcnProgramType type,
const uint8_t* code) :
m_programInfo(type),
GcnModule::GcnModule(const uint8_t* code) :
m_header(code),
m_programInfo(m_header.type()),
m_code(code)
{
}
@ -39,11 +37,6 @@ namespace sce::gcn
GcnCodeSlice slice(start, end);
auto insList = this->decodeShader(slice);
//if (this->name() == "PSSHDR_58D2050651B6B50A")
//{
// __debugbreak();
//}
// Generate global information
GcnAnalysisInfo analysisInfo;

View file

@ -22,9 +22,7 @@ namespace sce::gcn
class GcnModule
{
public:
GcnModule(
GcnProgramType type,
const uint8_t* code);
GcnModule(const uint8_t* code);
~GcnModule();
/**
@ -82,9 +80,9 @@ namespace sce::gcn
void dumpShader() const;
private:
GcnProgramInfo m_programInfo;
GcnHeader m_header;
const uint8_t* m_code;
GcnHeader m_header;
GcnProgramInfo m_programInfo;
const uint8_t* m_code;
GcnShaderResourceTable m_resourceTable;
};

View file

@ -6,6 +6,19 @@
namespace sce::gcn
{
enum class ShaderBinaryType : uint8_t
{
kPixelShader = 0, ///< PS stage shader.
kVertexShader = 1, ///< VS stage shader
kExportShader = 2,
kLocalShader = 3,
kComputeShader = 4, ///< CS stage shader.
kGeometryShader = 5,
kUnknown = 6,
kHullShader = 7, ///< HS stage shader.
kDomainShader = 8, ///< DS stage shader with embedded CS stage frontend shader.
} ShaderType;
struct ShaderBinaryInfo
{
uint8_t m_signature[7]; // 'OrbShdr'

View file

@ -12,9 +12,9 @@ namespace sce::gcn
{
public:
GcnShaderKey(
uint32_t crc, uint32_t hash)
uint32_t hash, uint32_t crc)
{
m_key = util::concat<uint64_t>(crc, hash);
m_key = util::concat<uint64_t>(hash, crc);
}
~GcnShaderKey() = default;
@ -29,6 +29,11 @@ namespace sce::gcn
return util::str::format("SHDR_%llX", m_key);
}
bool operator==(const GcnShaderKey& other) const
{
return m_key == other.m_key;
}
private:
uint64_t m_key;
};

View file

@ -77,4 +77,10 @@ namespace sce::Gnm
{
GnmShaderContext shaderContext = {};
};
struct GnmRenderState
{
GnmGraphicsState gp;
GnmComputeState cp;
};
} // namespace sce::Gnm

View file

@ -0,0 +1,84 @@
#include "GnmShader.h"
#include "Violet/VltShader.h"
#include "Gcn/GcnModule.h"
#include "Gcn/GcnShaderMeta.h"
LOG_CHANNEL(Graphic.Gnm.GnmShader);
using namespace sce::gcn;
using namespace sce::vlt;
namespace sce::Gnm
{
GnmShader::GnmShader() :
m_shader(nullptr)
{
}
GnmShader::GnmShader(const vlt::VltShaderKey* key,
const gcn::GcnModuleInfo* moduleInfo,
const GcnShaderMeta& meta,
const void* code)
{
const std::string name = key->toString();
LOG_DEBUG("Compiling shader %s", name.c_str());
GcnModule module(
reinterpret_cast<const uint8_t*>(code));
m_shader = module.compile(meta, *moduleInfo);
m_shader->setShaderKey(*key);
}
GnmShader::~GnmShader()
{
}
GcnShaderModuleSet::GcnShaderModuleSet()
{
}
GcnShaderModuleSet::~GcnShaderModuleSet()
{
}
GnmShader GcnShaderModuleSet::GetShaderModule(const VltShaderKey* key,
const GcnModuleInfo* moduleInfo,
const GcnShaderMeta& meta,
const void* code)
{
// Use the shader's unique key for the lookup
{
std::unique_lock<std::mutex> lock(m_mutex);
auto entry = m_modules.find(*key);
if (entry != m_modules.end())
{
return entry->second;
}
}
// This shader has not been compiled yet, so we have to create a
// new module. This takes a while, so we won't lock the structure.
GnmShader shader = GnmShader(key, moduleInfo, meta, code);
// Insert the new module into the lookup table. If another thread
// has compiled the same shader in the meantime, we should return
// that object instead and discard the newly created module.
{
std::unique_lock<std::mutex> lock(m_mutex);
auto status = m_modules.insert({ *key, shader });
if (!status.second)
{
return status.first->second;
}
}
return std::move(shader);
}
} // namespace sce::Gnm

View file

@ -0,0 +1,79 @@
#pragma once
#include "GnmCommon.h"
#include "Gcn/GcnModInfo.h"
#include "Violet/VltHash.h"
#include <mutex>
#include <unordered_map>
namespace sce::vlt
{
class VltShaderKey;
} // namespace sce::vlt
namespace sce::gcn
{
union GcnShaderMeta;
} // namespace sce::vlt
namespace sce::Gnm
{
/**
* \brief Common shader object
*
* Stores the compiled SPIR-V shader and the
* hash of the original gcn shader, which can be
* used to identify the shader.
*/
class GnmShader
{
public:
GnmShader();
GnmShader(const vlt::VltShaderKey* key,
const gcn::GcnModuleInfo* moduleInfo,
const GcnShaderMeta& meta,
const void* code);
~GnmShader();
vlt::Rc<VltShader> getShader() const
{
return m_shader;
}
private:
vlt::Rc<vlt::VltShader> m_shader;
};
/**
* \brief Shader module set
*
* Some applications may compile the same shader multiple
* times, so we should cache the resulting shader modules
* and reuse them rather than creating new ones. This
* class is thread-safe.
*/
class GcnShaderModuleSet
{
public:
GcnShaderModuleSet();
~GcnShaderModuleSet();
GnmShader GetShaderModule(
const vlt::VltShaderKey* key,
const gcn::GcnModuleInfo* moduleInfo,
const GcnShaderMeta& meta,
const void* code);
private:
std::mutex m_mutex;
std::unordered_map<
vlt::VltShaderKey,
GnmShader,
vlt::VltHash,
vlt::VltEq> m_modules;
};
} // namespace sce::Gnm

View file

@ -58,24 +58,27 @@ namespace sce::vlt
};
/**
* \brief Depth bounds range
*
* Stores depth bounds values.
*/
struct VltDepthBoundsRange
* \brief Depth bounds
*
* Stores depth bounds values.
*/
struct VltDepthBounds
{
float minDepthBounds;
float maxDepthBounds;
VkBool32 enableDepthBounds;
float minDepthBounds;
float maxDepthBounds;
bool operator==(const VltDepthBoundsRange& other) const
{
return minDepthBounds == other.minDepthBounds &&
bool operator==(const VltDepthBounds& other) const
{
return enableDepthBounds == other.enableDepthBounds &&
minDepthBounds == other.minDepthBounds &&
maxDepthBounds == other.maxDepthBounds;
}
bool operator!=(const VltDepthBoundsRange& other) const
bool operator!=(const VltDepthBounds& other) const
{
return minDepthBounds != other.minDepthBounds ||
return enableDepthBounds != other.enableDepthBounds ||
minDepthBounds != other.minDepthBounds ||
maxDepthBounds != other.maxDepthBounds;
}
};

View file

@ -84,24 +84,27 @@ namespace sce::vlt
m_device->createCommandList(queueType));
}
void VltContext::bindRenderTarget(
uint32_t slot,
const VltAttachment& target)
void VltContext::bindRenderTargets(const VltRenderTargets& targets)
{
m_state.cb.renderTargets.color[slot] = target;
// Set up default render pass ops
m_state.cb.renderTargets = targets;
resetFramebufferOps();
this->resetFramebufferOps();
m_flags.set(VltContextFlag::GpDirtyFramebuffer);
if (m_state.cb.framebuffer == nullptr || !m_state.cb.framebuffer->matchTargets(targets))
{
// Create a new framebuffer object next
// time we start rendering something
m_flags.set(VltContextFlag::GpDirtyFramebuffer);
}
else
{
// Don't redundantly spill the render pass if
// the same render targets are bound again
m_flags.clr(VltContextFlag::GpDirtyFramebuffer);
}
}
void VltContext::bindDepthRenderTarget(
const VltAttachment& depthTarget)
{
m_state.cb.renderTargets.depth = depthTarget;
m_flags.set(VltContextFlag::GpDirtyFramebuffer);
}
void VltContext::bindIndexBuffer(
const VltBufferSlice& buffer,
@ -484,8 +487,8 @@ namespace sce::vlt
m_state.gp.state.ds.enableDepthBoundsTest());
m_cmd->cmdSetDepthBounds(
m_state.dyn.depthBoundsRange.minDepthBounds,
m_state.dyn.depthBoundsRange.maxDepthBounds);
m_state.dyn.depthBounds.minDepthBounds,
m_state.dyn.depthBounds.maxDepthBounds);
}
}
@ -603,7 +606,8 @@ namespace sce::vlt
void VltContext::setViewports(
uint32_t viewportCount,
const VkViewport* viewports)
const VkViewport* viewports,
const VkRect2D* scissorRects)
{
if (m_state.gp.state.rs.viewportCount() != viewportCount)
{
@ -613,13 +617,13 @@ namespace sce::vlt
for (uint32_t i = 0; i < viewportCount; i++)
{
m_state.vp.viewports[i] = viewports[i];
m_state.vp.viewports[i] = viewports[i];
m_state.vp.scissorRects[i] = scissorRects[i];
// Vulkan viewports are not allowed to have a width
// of zero (but zero height is allowed),
// so we fall back to a dummy viewport
// Vulkan viewports are not allowed to have a width or
// height of zero, so we fall back to a dummy viewport
// and instead set an empty scissor rect, which is legal.
if (viewports[i].width == 0.0f)
if (viewports[i].width == 0.0f || viewports[i].height == 0.0f)
{
m_state.vp.viewports[i] = VkViewport{
0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f
@ -634,27 +638,6 @@ namespace sce::vlt
m_flags.set(VltContextFlag::GpDirtyViewport);
}
void VltContext::setScissors(
uint32_t scissorCount,
const VkRect2D* scissorRects)
{
// Assume count of scissor and viewport are always equal.
// In fact, these's only one scissor for Gnm
if (m_state.gp.state.rs.viewportCount() != scissorCount)
{
m_state.gp.state.rs.setViewportCount(scissorCount);
m_flags.set(VltContextFlag::GpDirtyPipelineState);
}
for (uint32_t i = 0; i < scissorCount; i++)
{
m_state.vp.scissorRects[i] = scissorRects[i];
}
m_flags.set(VltContextFlag::GpDirtyScissor);
}
void VltContext::setBlendConstants(
VltBlendConstants blendConstants)
{
@ -675,25 +658,19 @@ namespace sce::vlt
}
}
void VltContext::setDepthBoundsTestEnable(
VkBool32 depthBoundsTestEnable)
void VltContext::setDepthBounds(VltDepthBounds depthBounds)
{
if (m_state.gp.state.ds.enableDepthBoundsTest() != depthBoundsTestEnable)
if (m_state.dyn.depthBounds != depthBounds)
{
m_state.gp.state.ds.setEnableDepthBoundsTest(depthBoundsTestEnable);
m_flags.set(VltContextFlag::GpDirtyPipelineState);
}
}
void VltContext::setDepthBoundsRange(
VltDepthBoundsRange depthBoundsRange)
{
if (m_state.dyn.depthBoundsRange != depthBoundsRange)
{
m_state.dyn.depthBoundsRange = depthBoundsRange;
m_state.dyn.depthBounds = depthBounds;
m_flags.set(VltContextFlag::GpDirtyDepthBounds);
}
if (m_state.gp.state.ds.enableDepthBoundsTest() != depthBounds.enableDepthBounds)
{
m_state.gp.state.ds.setEnableDepthBoundsTest(depthBounds.enableDepthBounds);
m_flags.set(VltContextFlag::GpDirtyPipelineState);
}
}
void VltContext::setStencilReference(uint32_t reference)
@ -901,15 +878,6 @@ namespace sce::vlt
m_flags.set(VltContextFlag::GpDirtyPipelineState);
}
void VltContext::setBlendMask(
uint32_t attachment,
VkColorComponentFlags writeMask)
{
m_state.gp.state.cbBlend[attachment].setColorWriteMask(writeMask);
m_flags.set(VltContextFlag::GpDirtyPipelineState);
}
void VltContext::clearRenderTarget(
const Rc<VltImageView>& imageView,
VkImageAspectFlags clearAspects,
@ -2037,4 +2005,5 @@ namespace sce::vlt
}
} // namespace sce::vlt

View file

@ -76,22 +76,15 @@ namespace sce::vlt
void flushCommandList();
/**
* \brief Sets render targets
*
* \param [in] slot Slot number
* \param [in] targets Render targets to bind
*/
void bindRenderTarget(
uint32_t slot,
const VltAttachment& target);
* \brief Sets render targets
*
* Creates a framebuffer on the fly if necessary
* and binds it using \c bindFramebuffer.
* \param [in] targets Render targets to bind
*/
void bindRenderTargets(
const VltRenderTargets& targets);
/**
* \brief Sets depth render targets
*
* \param [in] targets Render targets to bind
*/
void bindDepthRenderTarget(
const VltAttachment& depthTarget);
/**
* \brief Binds index buffer
@ -226,36 +219,17 @@ namespace sce::vlt
const VltBlendMode& blendMode);
/**
* \brief Sets write mask for an attachment
* \brief Sets viewports
*
* \param [in] attachment The attachment index
* \param [in] writeMask The writeMask
* \param [in] viewportCount Number of viewports
* \param [in] viewports The viewports
* \param [in] scissorRects Schissor rectangles
*/
void setBlendMask(
uint32_t attachment,
VkColorComponentFlags writeMask);
/**
* \brief Sets viewports
*
* \param [in] viewportCount Number of viewports
* \param [in] viewports The viewports
* \param [in] scissorRects Schissor rectangles
*/
void setViewports(
uint32_t viewportCount,
const VkViewport* viewports);
const VkViewport* viewports,
const VkRect2D* scissorRects);
/**
* \brief Sets viewports
*
* \param [in] scissorCount Number of schissor rectangles
* \param [in] scissorRects Schissor rectangles
*/
void setScissors(
uint32_t scissorCount,
const VkRect2D* scissorRects);
/**
* \brief Sets blend constants
@ -278,22 +252,15 @@ namespace sce::vlt
void setDepthBias(
VltDepthBias depthBias);
/**
* \brief Sets depth bounds enable state
*
* Enables or disables the depth bounds test.
*/
void setDepthBoundsTestEnable(
VkBool32 depthBoundsTestEnable);
/**
* \brief Sets depth bounds
*
* Updates the depth bounds values.
* \param [in] depthBoundsRange Depth bounds range
* Enables or disables the depth bounds test,
* and updates the values if necessary.
* \param [in] depthBounds Depth bounds
*/
void setDepthBoundsRange(
VltDepthBoundsRange depthBoundsRange);
void setDepthBounds(
VltDepthBounds depthBounds);
/**
* \brief Sets stencil reference

View file

@ -37,7 +37,6 @@ namespace sce::vlt
GpDirtyDepthBounds, ///< Depth bounds have changed
GpDirtyStencilRef, ///< Stencil reference has changed
GpDirtyViewport, ///< Viewport has changed
GpDirtyScissor, ///< Scissor has changed
GpDirtyPredicate, ///< Predicate has changed
GpDynamicBlendConstants, ///< Blend constants are dynamic
GpDynamicDepthBias, ///< Depth bias is dynamic
@ -125,10 +124,10 @@ namespace sce::vlt
struct VltDynamicState
{
VltBlendConstants blendConstants = { 0.0f, 0.0f, 0.0f, 0.0f };
VltDepthBias depthBias = { 0.0f, 0.0f, 0.0f };
VltDepthBoundsRange depthBoundsRange = { 0.0f, 1.0f };
uint32_t stencilReference = 0;
VltBlendConstants blendConstants = { 0.0f, 0.0f, 0.0f, 0.0f };
VltDepthBias depthBias = { 0.0f, 0.0f, 0.0f };
VltDepthBounds depthBounds = { false, 0.0f, 1.0f };
uint32_t stencilReference = 0;
};
struct VltCondRenderState

View file

@ -149,7 +149,6 @@ namespace sce::vlt
dynamicStates[dynamicStateCount++] = VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE;
}
if (state.useDynamicBlendConstants())
dynamicStates[dynamicStateCount++] = VK_DYNAMIC_STATE_BLEND_CONSTANTS;

View file

@ -107,8 +107,6 @@ namespace sce::vlt
m_flags.set(VltShaderFlag::ExportsViewportIndexLayerFromVertexStage);
}
}
updateShaderKey(code);
}
VltShader::~VltShader()
@ -168,7 +166,10 @@ namespace sce::vlt
// Do not fix binding id if we read from a external binary file.
m_idOffsets.clear();
updateShaderKey(m_code.decompress());
auto code = m_code.decompress();
alg::Sha1Hash hash = alg::Sha1Hash::compute(code.data(), code.size());
m_key = VltShaderKey(m_stage, hash);
m_hash = m_key.hash();
}
void VltShader::eliminateInput(SpirvCodeBuffer& code, uint32_t location)
@ -380,14 +381,6 @@ namespace sce::vlt
}
}
void VltShader::updateShaderKey(const gcn::SpirvCodeBuffer& code)
{
alg::Sha1Hash hash = alg::Sha1Hash::compute(code.data(), code.size());
m_key = VltShaderKey(m_stage, hash);
m_hash = m_key.hash();
}
VltShaderModule::VltShaderModule() :
m_device(nullptr), m_stage()
{

View file

@ -251,6 +251,16 @@ namespace sce::vlt
return m_key;
}
/**
* \brief Sets the shader key
* \param [in] key Unique key
*/
void setShaderKey(const VltShaderKey& key)
{
m_key = key;
m_hash = key.hash();
}
/**
* \brief Get lookup hash
*
@ -287,7 +297,6 @@ namespace sce::vlt
}
private:
void updateShaderKey(const gcn::SpirvCodeBuffer& code);
static void eliminateInput(gcn::SpirvCodeBuffer& code, uint32_t location);
@ -306,8 +315,6 @@ namespace sce::vlt
size_t m_o1IdxOffset = 0;
size_t m_o1LocOffset = 0;
};
/**

View file

@ -4,7 +4,7 @@ namespace sce::vlt
{
VltShaderKey::VltShaderKey() :
m_type(0),
m_sha1(alg::Sha1Hash::compute(nullptr, 0))
m_key(0, 0)
{
}
@ -36,7 +36,7 @@ namespace sce::vlt
prefix = "";
}
return util::str::formatex(prefix, m_sha1.toString());
return util::str::formatex(prefix, m_key.name());
}
size_t VltShaderKey::hash() const
@ -44,14 +44,15 @@ namespace sce::vlt
VltHashState result;
result.add(uint32_t(m_type));
for (uint32_t i = 0; i < 5; i++)
result.add(m_sha1.dword(i));
uint64_t key = m_key.key();
result.add(key);
return result;
}
bool VltShaderKey::eq(const VltShaderKey& key) const
bool VltShaderKey::eq(const VltShaderKey& other) const
{
return m_type == key.m_type && m_sha1 == key.m_sha1;
return m_type == other.m_type &&
m_key == other.m_key;
}
} // namespace sce::vlt

View file

@ -1,8 +1,8 @@
#pragma once
#include "Sha1Hash.h"
#include "VltCommon.h"
#include "VltHash.h"
#include "Gcn/GcnShaderKey.h"
namespace sce::vlt
{
@ -32,9 +32,9 @@ namespace sce::vlt
*/
VltShaderKey(
VkShaderStageFlagBits stage,
alg::Sha1Hash hash) :
gcn::GcnShaderKey key) :
m_type(stage),
m_sha1(hash)
m_key(key)
{
}
@ -53,14 +53,14 @@ namespace sce::vlt
/**
* \brief Checks whether two keys are equal
*
* \param [in] key The shader key to compare to
* \param [in] other The shader key to compare to
* \returns \c true if the two keys are equal
*/
bool eq(const VltShaderKey& key) const;
bool eq(const VltShaderKey& other) const;
private:
VkShaderStageFlags m_type;
alg::Sha1Hash m_sha1;
gcn::GcnShaderKey m_key;
};
} // namespace sce::vlt