adjust render state

This commit is contained in:
Asuka 2022-07-02 04:56:39 +08:00
parent bd12022637
commit 379a04b031
17 changed files with 377 additions and 251 deletions

View file

@ -57,6 +57,7 @@
</ClInclude>
<ClInclude Include="Graphics\Gnm\GnmGpuLabel.h" />
<ClInclude Include="Graphics\Gnm\GnmInitializer.h" />
<ClInclude Include="Graphics\Gnm\GnmLabelManager.h" />
<ClInclude Include="Graphics\Gnm\GnmLimits.h" />
<ClInclude Include="Graphics\Gnm\GnmRenderState.h" />
<ClInclude Include="Graphics\Gnm\GnmResourceFactory.h" />
@ -93,7 +94,6 @@
<ClInclude Include="Graphics\Sce\SceComputeQueue.h" />
<ClInclude Include="Graphics\Sce\SceGnmDriver.h" />
<ClInclude Include="Graphics\Sce\SceGpuQueue.h" />
<ClInclude Include="Graphics\Sce\SceLabelManager.h" />
<ClInclude Include="Graphics\Sce\ScePresenter.h" />
<ClInclude Include="Graphics\Sce\SceResource.h" />
<ClInclude Include="Graphics\Sce\SceResourceTracker.h" />
@ -345,6 +345,7 @@
</ClCompile>
<ClCompile Include="Graphics\Gnm\GnmGpuLabel.cpp" />
<ClCompile Include="Graphics\Gnm\GnmInitializer.cpp" />
<ClCompile Include="Graphics\Gnm\GnmLabelManager.cpp" />
<ClCompile Include="Graphics\Gnm\GnmResourceFactory.cpp" />
<ClCompile Include="Graphics\Gnm\GnmCommandBuffer.cpp" />
<ClCompile Include="Graphics\Gnm\GnmCommandBufferDispatch.cpp" />
@ -363,7 +364,6 @@
<ClCompile Include="Graphics\Sce\SceComputeQueue.cpp" />
<ClCompile Include="Graphics\Sce\SceGnmDriver.cpp" />
<ClCompile Include="Graphics\Sce\SceGpuQueue.cpp" />
<ClCompile Include="Graphics\Sce\SceLabelManager.cpp" />
<ClCompile Include="Graphics\Sce\ScePresenter.cpp" />
<ClCompile Include="Graphics\Sce\SceResource.cpp" />
<ClCompile Include="Graphics\Sce\SceResourceTracker.cpp" />

View file

@ -925,9 +925,6 @@
<ClInclude Include="Graphics\Gnm\GnmGpuLabel.h">
<Filter>Source Files\Graphics\Gnm</Filter>
</ClInclude>
<ClInclude Include="Graphics\Sce\SceLabelManager.h">
<Filter>Source Files\Graphics\Sce</Filter>
</ClInclude>
<ClInclude Include="SceModules\SceNpCommon\sce_npcommon_types.h">
<Filter>SceModules\SceNpCommon</Filter>
</ClInclude>
@ -976,6 +973,9 @@
<ClInclude Include="Graphics\Gnm\GnmLimits.h">
<Filter>Source Files\Graphics\Gnm</Filter>
</ClInclude>
<ClInclude Include="Graphics\Gnm\GnmLabelManager.h">
<Filter>Source Files\Graphics\Gnm</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Loader\EbootObject.cpp">
@ -1680,9 +1680,6 @@
<ClCompile Include="Graphics\Gnm\GnmGpuLabel.cpp">
<Filter>Source Files\Graphics\Gnm</Filter>
</ClCompile>
<ClCompile Include="Graphics\Sce\SceLabelManager.cpp">
<Filter>Source Files\Graphics\Sce</Filter>
</ClCompile>
<ClCompile Include="Graphics\Gcn\GcnInstructionUtil.cpp">
<Filter>Source Files\Graphics\Gcn</Filter>
</ClCompile>
@ -1716,6 +1713,9 @@
<ClCompile Include="Graphics\Gnm\GnmShader.cpp">
<Filter>Source Files\Graphics\Gnm</Filter>
</ClCompile>
<ClCompile Include="Graphics\Gnm\GnmLabelManager.cpp">
<Filter>Source Files\Graphics\Gnm</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Text Include="Emulator\TLSStub.asm">

View file

@ -3,6 +3,7 @@
#include "Emulator.h"
#include "GnmRenderState.h"
#include "GnmGpuLabel.h"
#include "GnmLabelManager.h"
#include "VirtualGPU.h"
#include "Gcn/GcnShaderRegField.h"
@ -10,7 +11,6 @@
#include "Sce/SceGpuQueue.h"
#include "Sce/SceResource.h"
#include "Sce/SceResourceTracker.h"
#include "Sce/SceLabelManager.h"
#include "Violet/VltCmdList.h"
#include "Violet/VltDevice.h"
@ -69,7 +69,7 @@ namespace sce::Gnm
const uint32_t* GnmCommandBuffer::findUserData(
const gcn::GcnShaderResource& res,
uint32_t eudIndex,
const UserDataArray& userData)
const UserDataSlot& userData)
{
const uint32_t* registerData = nullptr;
if (!res.inEud)
@ -208,7 +208,7 @@ namespace sce::Gnm
void GnmCommandBuffer::bindResource(
VkPipelineStageFlags stage,
const GcnShaderResourceTable& table,
const UserDataArray& userData)
const UserDataSlot& userData)
{
// Find EUD
uint32_t eudIndex = findUsageRegister(table, kShaderInputUsagePtrExtendedUserData);

View file

@ -19,7 +19,6 @@
namespace sce
{
class SceResourceTracker;
class SceLabelManager;
enum class SceQueueType;
namespace vlt
@ -27,16 +26,16 @@ namespace sce
class VltDevice;
class VltContext;
class VltCommandList;
} // namespace vlt
} // namespace sce
}
}
namespace sce::Gnm
{
class Buffer;
class Texture;
class Sampler;
class GnmLabelManager;
class GnmCommandBuffer
{
@ -430,7 +429,7 @@ namespace sce::Gnm
const uint32_t* findUserData(
const gcn::GcnShaderResource& res,
uint32_t eudIndex,
const UserDataArray& userData);
const UserDataSlot& userData);
void setCsShader(
GnmShaderContext& ctx,
@ -461,7 +460,7 @@ namespace sce::Gnm
void bindResource(
VkPipelineStageFlags stage,
const gcn::GcnShaderResourceTable& table,
const UserDataArray& userData);
const UserDataSlot& userData);
void commitComputeState(
GnmShaderContext& ctx);
@ -497,10 +496,14 @@ namespace sce::Gnm
vlt::Rc<vlt::VltContext> m_context;
GnmResourceFactory m_factory;
GnmRenderState m_state;
GnmContextFlags m_flags;
SceResourceTracker* m_tracker = nullptr;
SceLabelManager* m_labelManager = nullptr;
GnmLabelManager* m_labelManager = nullptr;
std::unique_ptr<GnmInitializer> m_initializer;
gcn::GcnModuleInfo m_moduleInfo;
private:
};

View file

@ -3,10 +3,10 @@
#include "GnmBuffer.h"
#include "GnmGpuLabel.h"
#include "GnmInitializer.h"
#include "GnmLabelManager.h"
#include "GnmTexture.h"
#include "Sce/SceGpuQueue.h"
#include "Sce/SceLabelManager.h"
#include "Violet/VltCmdList.h"
#include "Violet/VltContext.h"
#include "Violet/VltDevice.h"
@ -108,7 +108,7 @@ namespace sce::Gnm
void GnmCommandBufferDispatch::setVsharpInUserData(ShaderStage stage, uint32_t startUserDataSlot, const Buffer* buffer)
{
std::memcpy(&m_state.sc.userData[startUserDataSlot], buffer, sizeof(Buffer));
std::memcpy(&m_state.cp.sc.userData[startUserDataSlot], buffer, sizeof(Buffer));
}
void GnmCommandBufferDispatch::setTsharpInUserData(ShaderStage stage, uint32_t startUserDataSlot, const Texture* tex)
@ -295,7 +295,7 @@ namespace sce::Gnm
void GnmCommandBufferDispatch::setCsShader(const gcn::CsStageRegisters* computeData, uint32_t shaderModifier)
{
GnmCommandBuffer::setCsShader(m_state.sc, computeData, shaderModifier);
GnmCommandBuffer::setCsShader(m_state.cp.sc, computeData, shaderModifier);
}
void GnmCommandBufferDispatch::writeReleaseMemEventWithInterrupt(ReleaseMemEventType eventType, EventWriteDest dstSelector, void* dstGpuAddr, EventWriteSource srcSelector, uint64_t immValue, CacheAction cacheAction, CachePolicy writePolicy)
@ -325,7 +325,7 @@ namespace sce::Gnm
void GnmCommandBufferDispatch::commitComputeState()
{
GnmCommandBuffer::commitComputeState(m_state.sc);
GnmCommandBuffer::commitComputeState(m_state.cp.sc);
m_initializer->flush();
}
@ -333,15 +333,15 @@ namespace sce::Gnm
void GnmCommandBufferDispatch::updateMetaBufferInfo(
VkPipelineStageFlags stage, uint32_t startRegister, const Buffer* vsharp)
{
GcnBufferMeta meta = populateBufferMeta(vsharp);
m_state.sc.meta.cs.bufferInfos[startRegister] = meta;
GcnBufferMeta meta = populateBufferMeta(vsharp);
m_state.cp.sc.meta.cs.bufferInfos[startRegister] = meta;
}
void GnmCommandBufferDispatch::updateMetaTextureInfo(
VkPipelineStageFlags stage, uint32_t startRegister, bool isDepth, const Texture* tsharp)
{
GcnTextureMeta meta = populateTextureMeta(tsharp, isDepth);
m_state.sc.meta.cs.textureInfos[startRegister] = meta;
GcnTextureMeta meta = populateTextureMeta(tsharp, isDepth);
m_state.cp.sc.meta.cs.textureInfos[startRegister] = meta;
}
void GnmCommandBufferDispatch::setClipControl(ClipControl reg)

View file

@ -165,9 +165,7 @@ namespace sce::Gnm
const Texture* tsharp) override;
private:
GnmComputeState m_state = {};
};
} // namespace sce::Gnm

View file

@ -2,17 +2,16 @@
#include "GnmBuffer.h"
#include "GnmConverter.h"
#include "GnmGpuLabel.h"
#include "GnmSampler.h"
#include "GnmSharpBuffer.h"
#include "GnmTexture.h"
#include "GnmGpuLabel.h"
#include "GpuAddress/GnmGpuAddress.h"
#include "Gcn/GcnUtil.h"
#include "Platform/PlatFile.h"
#include "Sce/SceGpuQueue.h"
#include "Sce/SceResourceTracker.h"
#include "Sce/SceLabelManager.h"
#include "Sce/SceVideoOut.h"
#include "Violet/VltContext.h"
#include "Violet/VltDevice.h"
@ -31,15 +30,6 @@ using namespace sce::gcn;
namespace sce::Gnm
{
// Use this to break on a shader you want to debug.
#define SHADER_DEBUG_BREAK(mod, token) \
if (mod.name() == token) \
{ \
__debugbreak(); \
}
GnmCommandBufferDraw::GnmCommandBufferDraw(vlt::VltDevice* device) :
GnmCommandBuffer(device)
{
@ -57,6 +47,10 @@ namespace sce::Gnm
// We do some initialize work here.
GnmCommandBuffer::initializeDefaultHardwareState();
initDefaultRenderState();
m_flags.clrAll();
m_context->beginRecording(
m_device->createCommandList(VltQueueType::Graphics));
}
@ -68,22 +62,15 @@ namespace sce::Gnm
void GnmCommandBufferDraw::setPrimitiveSetup(PrimitiveSetup reg)
{
VkFrontFace frontFace = reg.getFrontFace() == kPrimitiveSetupFrontFaceCcw ?
VK_FRONT_FACE_COUNTER_CLOCKWISE : VK_FRONT_FACE_CLOCKWISE;
VkFrontFace frontFace = reg.getFrontFace() == kPrimitiveSetupFrontFaceCcw ? VK_FRONT_FACE_COUNTER_CLOCKWISE : VK_FRONT_FACE_CLOCKWISE;
VkPolygonMode polyMode = cvt::convertPolygonMode(reg.getPolygonModeFront());
VkCullModeFlags cullMode = cvt::convertCullMode(reg.getCullFace());
VltRasterizerState rs = {
polyMode,
cullMode,
frontFace,
VK_FALSE,
VK_FALSE,
VK_SAMPLE_COUNT_1_BIT,
VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT
};
m_state.gp.rs.state.polygonMode = polyMode;
m_state.gp.rs.state.cullMode = cullMode;
m_state.gp.rs.state.frontFace = frontFace;
m_context->setRasterizerState(rs);
m_flags.set(GnmContextFlag::DirtyRasterizerState);
}
void GnmCommandBufferDraw::setScreenScissor(int32_t left, int32_t top, int32_t right, int32_t bottom)
@ -93,7 +80,10 @@ namespace sce::Gnm
scissor.offset.y = top;
scissor.extent.width = right - left;
scissor.extent.height = bottom - top;
m_context->setScissors(1, &scissor);
m_state.gp.rs.scissors[0] = scissor;
m_flags.set(GnmContextFlag::DirtyViewportScissor);
}
void GnmCommandBufferDraw::setViewport(uint32_t viewportId, float dmin, float dmax, const float scale[3], const float offset[3])
@ -121,7 +111,15 @@ namespace sce::Gnm
viewport.minDepth = dmin;
viewport.maxDepth = dmax;
m_context->setViewports(1, &viewport);
// Is this correct to always use max viewport id?
if (viewportId > m_state.gp.rs.numViewports)
{
m_state.gp.rs.numViewports = viewportId;
}
m_state.gp.rs.viewports[viewportId] = viewport;
m_flags.set(GnmContextFlag::DirtyViewportScissor);
}
void GnmCommandBufferDraw::setHardwareScreenOffset(uint32_t offsetX, uint32_t offsetY)
@ -136,10 +134,11 @@ namespace sce::Gnm
void GnmCommandBufferDraw::setPsShaderUsage(const uint32_t* inputTable, uint32_t numItems)
{
auto& ctx = m_state.sc[kShaderStagePs];
auto& ctx = m_state.gp.sc[kShaderStagePs];
std::transform(inputTable, inputTable + numItems,
ctx.meta.ps.semanticMapping.begin(),
[](const uint32_t reg) {
[](const uint32_t reg)
{
return *reinterpret_cast<const PixelSemanticMapping*>(&reg);
});
ctx.meta.ps.inputSemanticCount = numItems;
@ -152,7 +151,7 @@ namespace sce::Gnm
void GnmCommandBufferDraw::setPsShader(const gcn::PsStageRegisters* psRegs)
{
auto& ctx = m_state.sc[kShaderStagePs];
auto& ctx = m_state.gp.sc[kShaderStagePs];
ctx.code = psRegs->getCodeAddress();
const SPI_SHADER_PGM_RSRC2_PS* rsrc2 = reinterpret_cast<const SPI_SHADER_PGM_RSRC2_PS*>(&psRegs->spiShaderPgmRsrc2Ps);
@ -179,11 +178,11 @@ namespace sce::Gnm
void GnmCommandBufferDraw::setVsShader(const gcn::VsStageRegisters* vsRegs, uint32_t shaderModifier)
{
auto& ctx = m_state.sc[kShaderStageVs];
auto& ctx = m_state.gp.sc[kShaderStageVs];
ctx.code = vsRegs->getCodeAddress();
const SPI_SHADER_PGM_RSRC2_VS* rsrc2 = reinterpret_cast<const SPI_SHADER_PGM_RSRC2_VS*>(&vsRegs->spiShaderPgmRsrc2Vs);
ctx.meta.vs.userSgprCount = rsrc2->user_sgpr;
ctx.meta.vs.userSgprCount = rsrc2->user_sgpr;
}
void GnmCommandBufferDraw::setEmbeddedVsShader(EmbeddedVsShader shaderId, uint32_t shaderModifier)
@ -255,7 +254,7 @@ namespace sce::Gnm
0x61, 0xDE, 0xE7, 0xD1, 0x00, 0x00, 0x00, 0x00, 0x98, 0xE5, 0xCA, 0xB9
};
auto& ctx = m_state.sc[kShaderStageVs];
auto& ctx = m_state.gp.sc[kShaderStageVs];
ctx.code = reinterpret_cast<const void*>(embeddedVsShaderFullScreen);
ctx.meta.vs.userSgprCount = 0;
}
@ -266,35 +265,42 @@ namespace sce::Gnm
void GnmCommandBufferDraw::setVsharpInUserData(ShaderStage stage, uint32_t startUserDataSlot, const Buffer* buffer)
{
std::memcpy(&m_state.sc[stage].userData[startUserDataSlot], buffer, sizeof(Buffer));
std::memcpy(&m_state.gp.sc[stage].userData[startUserDataSlot], buffer, sizeof(Buffer));
}
void GnmCommandBufferDraw::setTsharpInUserData(ShaderStage stage, uint32_t startUserDataSlot, const Texture* tex)
{
std::memcpy(&m_state.sc[stage].userData[startUserDataSlot], tex, sizeof(Texture));
std::memcpy(&m_state.gp.sc[stage].userData[startUserDataSlot], tex, sizeof(Texture));
}
void GnmCommandBufferDraw::setSsharpInUserData(ShaderStage stage, uint32_t startUserDataSlot, const Sampler* sampler)
{
std::memcpy(&m_state.sc[stage].userData[startUserDataSlot], sampler, sizeof(Sampler));
std::memcpy(&m_state.gp.sc[stage].userData[startUserDataSlot], sampler, sizeof(Sampler));
}
void GnmCommandBufferDraw::setPointerInUserData(ShaderStage stage, uint32_t startUserDataSlot, void* gpuAddr)
{
std::memcpy(&m_state.sc[stage].userData[startUserDataSlot], gpuAddr, sizeof(void*));
std::memcpy(&m_state.gp.sc[stage].userData[startUserDataSlot], gpuAddr, sizeof(void*));
}
void GnmCommandBufferDraw::setUserDataRegion(ShaderStage stage, uint32_t startUserDataSlot, const uint32_t* userData, uint32_t numDwords)
{
std::memcpy(&m_state.sc[stage].userData[startUserDataSlot], userData, numDwords * sizeof(uint32_t));
std::memcpy(&m_state.gp.sc[stage].userData[startUserDataSlot], userData, numDwords * sizeof(uint32_t));
}
void GnmCommandBufferDraw::setRenderTarget(uint32_t rtSlot, RenderTarget const* target)
{
auto resource = m_tracker->find(target->getBaseAddress());
do
Rc<VltImageView> targetView = nullptr;
do
{
Rc<VltImageView> targetView = nullptr;
if (target == nullptr)
{
break;
}
auto resource = m_tracker->find(target->getBaseAddress());
if (!resource)
{
// The render target is not a display buffer registered in video out,
@ -306,6 +312,8 @@ namespace sce::Gnm
rtTexture.initFromRenderTarget(target, false);
m_initializer->initTexture(rtRes.image, &rtTexture);
targetView = rtRes.imageView;
m_tracker->track(rtRes);
}
else
@ -320,31 +328,32 @@ namespace sce::Gnm
targetView = rtRes.imageView;
}
} while (false);
VltAttachment attachment =
{
if (m_state.gp.om.renderTargets.color[rtSlot].view != targetView)
{
m_state.gp.om.renderTargets.color[rtSlot] = {
targetView,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
};
m_context->bindRenderTarget(rtSlot, attachment);
} while (false);
m_flags.set(GnmContextFlag::DirtyRenderTargets);
}
}
void GnmCommandBufferDraw::setDepthRenderTarget(DepthRenderTarget const* depthTarget)
{
Rc<VltImageView> depthView = nullptr;
do
{
if (depthTarget == nullptr)
{
m_context->bindDepthRenderTarget(VltAttachment{});
break;
}
auto zBufferAddr = depthTarget->getZReadAddress();
auto resource = m_tracker->find(zBufferAddr);
Rc<VltImageView> depthView = nullptr;
if (!resource)
{
// create a new depth image and track it
@ -374,13 +383,16 @@ namespace sce::Gnm
}
}
VltAttachment attachment = {
} while (false);
if (m_state.gp.om.renderTargets.depth.view != depthView)
{
m_state.gp.om.renderTargets.depth = {
depthView,
VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL
};
m_context->bindDepthRenderTarget(attachment);
} while (false);
m_flags.set(GnmContextFlag::DirtyRenderTargets);
}
}
void GnmCommandBufferDraw::setDepthClearValue(float clearValue)
@ -399,11 +411,18 @@ namespace sce::Gnm
void GnmCommandBufferDraw::setRenderTargetMask(uint32_t mask)
{
bool dirty = false;
auto writeMasks = cvt::convertRenderTargetMask(mask);
for (uint32_t attachment = 0; attachment != writeMasks.size(); ++attachment)
for (uint32_t i = 0; i != writeMasks.size(); ++i)
{
m_context->setBlendMask(
attachment, writeMasks[attachment]);
dirty |= m_state.gp.om.blendModes[i].writeMask == writeMasks[i];
m_state.gp.om.blendModes[i].writeMask = writeMasks[i];
}
if (dirty)
{
m_flags.set(GnmContextFlag::DirtyBlendState);
}
}
@ -417,11 +436,11 @@ namespace sce::Gnm
VkBlendFactor alphaDstFactor = cvt::convertBlendMultiplier(blendControl.getAlphaEquationDestinationMultiplier());
VkBlendOp alphaBlendOp = cvt::convertBlendFunc(blendControl.getAlphaEquationBlendFunction());
VkColorComponentFlags fullMask =
VK_COLOR_COMPONENT_R_BIT |
VK_COLOR_COMPONENT_G_BIT |
VK_COLOR_COMPONENT_B_BIT |
VK_COLOR_COMPONENT_A_BIT;
VkColorComponentFlags fullMask =
VK_COLOR_COMPONENT_R_BIT |
VK_COLOR_COMPONENT_G_BIT |
VK_COLOR_COMPONENT_B_BIT |
VK_COLOR_COMPONENT_A_BIT;
// Here we set color write mask to fullMask.
// The real mask value should be set through setRenderTargetMask call.
@ -450,9 +469,9 @@ namespace sce::Gnm
{
LOG_ASSERT(depthControl.stencilEnable == false, "stencil test not supported yet.");
VkCompareOp depthCmpOp = cvt::convertCompareFunc(depthControl.getDepthControlZCompareFunction());
VkCompareOp depthCmpOp = cvt::convertCompareFunc(depthControl.getDepthControlZCompareFunction());
VkCompareOp stencilFront = cvt::convertCompareFunc(depthControl.getStencilFunction());
VkCompareOp stencilBack = cvt::convertCompareFunc(depthControl.getStencilFunctionBack());
VkCompareOp stencilBack = cvt::convertCompareFunc(depthControl.getStencilFunctionBack());
VkStencilOpState frontOp = {};
frontOp.compareOp = stencilFront;
@ -485,7 +504,7 @@ namespace sce::Gnm
// In Gnm, when depth clear enable and HTILE compress disable
// all writes to the depth buffer will use the depth clear value set by
// DrawCommandBuffer::setDepthClearValue() instead of the fragment's depth value.
//
//
// For vulkan, we use depth bound test to emulate this somehow.
// We first set the depth clear value to clear depth buffer once render pass begin.
// Then force depth bound test failed to leave depth buffer untouched.
@ -497,8 +516,8 @@ namespace sce::Gnm
m_context->setDepthBoundsTestEnable(VK_TRUE);
VltDepthBoundsRange depthBounds;
depthBounds.minDepthBounds = 1.0;
depthBounds.maxDepthBounds = 0.0;
depthBounds.minDepthBounds = 1.0;
depthBounds.maxDepthBounds = 0.0;
m_context->setDepthBoundsRange(depthBounds);
m_state.ds.dbClearDepth = true;
@ -508,8 +527,6 @@ namespace sce::Gnm
m_context->setDepthBoundsTestEnable(VK_FALSE);
m_state.ds.dbClearDepth = false;
}
}
void GnmCommandBufferDraw::setVgtControl(uint8_t primGroupSizeMinusOne)
@ -519,7 +536,7 @@ namespace sce::Gnm
void GnmCommandBufferDraw::setPrimitiveType(PrimitiveType primType)
{
VkPrimitiveTopology topology = cvt::convertPrimitiveType(primType);
// TODO:
// This is a temporary solution, mainly for embedded vertex shader.
// For a primitive type which is not supported by vulkan natively,
@ -753,16 +770,17 @@ namespace sce::Gnm
switch (m_state.ia.topology)
{
case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
{
indexes.resize(indexCount);
std::generate(indexes.begin(), indexes.end(),
[n = 0]() mutable -> uint16_t { return n++; });
}
break;
default:
LOG_ASSERT(false, "topology type not supported.");
case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
{
indexes.resize(indexCount);
std::generate(indexes.begin(), indexes.end(),
[n = 0]() mutable -> uint16_t
{ return n++; });
}
break;
default:
LOG_ASSERT(false, "topology type not supported.");
break;
}
return generateIndexBuffer(indexes.data(), sizeof(uint16_t) * indexes.size());
@ -783,9 +801,9 @@ namespace sce::Gnm
uint32_t semanticCount = semanticTable.size();
for (uint32_t i = 0; i != semanticCount; ++i)
{
auto& sema = semanticTable[i];
uint32_t offsetInDwords = sema.m_semantic * ShaderConstantDwordSize::kDwordSizeVertexBuffer;
const Buffer* vtxBuffer = reinterpret_cast<const Buffer*>(vtxTable + offsetInDwords);
auto& sema = semanticTable[i];
uint32_t offsetInDwords = sema.m_semantic * ShaderConstantDwordSize::kDwordSizeVertexBuffer;
const Buffer* vtxBuffer = reinterpret_cast<const Buffer*>(vtxTable + offsetInDwords);
vtxData[i].data = vtxBuffer->getBaseAddress();
vtxData[i].stride = vtxBuffer->getStride();
@ -796,7 +814,7 @@ namespace sce::Gnm
bool isSingleBinding = true;
// If all left vertex attribute data start address is within the first and second
// vertex address of the first attribute data,
// vertex address of the first attribute data,
// we think the game uses a single vertex buffer binding.
// Otherwise we use multiple bindings.
for (uint32_t i = 1; i != semanticCount; ++i)
@ -824,14 +842,14 @@ namespace sce::Gnm
vsharp->getStride());
}
void GnmCommandBufferDraw::updateVertexBinding(GcnModule& vsModule)
void GnmCommandBufferDraw::updateVertexBinding(GnmShader& vsModule)
{
auto& ctx = m_state.sc[kShaderStageVs];
auto& resTable = vsModule.getResourceTable();
// Find fetch shader
VertexInputSemanticTable semaTable;
auto fsCode = findFetchShader(resTable, ctx.userData);
auto fsCode = findFetchShader(resTable, ctx.userData);
if (fsCode != nullptr)
{
GcnFetchShader fs(reinterpret_cast<const uint8_t*>(fsCode));
@ -871,11 +889,9 @@ namespace sce::Gnm
// Attributes
attributes[i].location = sema.m_semantic;
attributes[i].binding = singleBinding ?
0 : sema.m_semantic;
attributes[i].binding = singleBinding ? 0 : sema.m_semantic;
attributes[i].format = cvt::convertDataFormat(vsharp->getDataFormat());
attributes[i].offset = singleBinding ?
reinterpret_cast<size_t>(vsharp->getBaseAddress()) - firstAttributeOffset : 0;
attributes[i].offset = singleBinding ? reinterpret_cast<size_t>(vsharp->getBaseAddress()) - firstAttributeOffset : 0;
// Bindings
bindings[i].binding = sema.m_semantic;
@ -883,7 +899,7 @@ namespace sce::Gnm
bindings[i].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
// Fix element count
sema.m_sizeInElements =
sema.m_sizeInElements =
std::min(static_cast<uint32_t>(sema.m_sizeInElements), vsharp->getDataFormat().getNumComponents());
}
@ -929,7 +945,7 @@ namespace sce::Gnm
// Update vertex input
auto& ctx = m_state.sc[kShaderStageVs];
do
do
{
if (ctx.code == nullptr)
{
@ -966,7 +982,7 @@ namespace sce::Gnm
{
auto& ctx = m_state.sc[kShaderStagePs];
do
do
{
if (ctx.code == nullptr)
{
@ -1018,7 +1034,7 @@ namespace sce::Gnm
const void* GnmCommandBufferDraw::findFetchShader(
const gcn::GcnShaderResourceTable& table,
const UserDataArray& userData)
const UserDataSlot& userData)
{
const void* fsCode = nullptr;
@ -1034,7 +1050,6 @@ namespace sce::Gnm
{
// This is the last cmd for a command buffer submission,
// we can do some finish works before submit and present.
}
void GnmCommandBufferDraw::updateMetaTextureInfo(
@ -1153,17 +1168,147 @@ namespace sce::Gnm
void GnmCommandBufferDraw::pushMarker(const char* debugString)
{
//throw std::logic_error("The method or operation is not implemented.");
// throw std::logic_error("The method or operation is not implemented.");
}
void GnmCommandBufferDraw::pushMarker(const char* debugString, uint32_t argbColor)
{
//throw std::logic_error("The method or operation is not implemented.");
// throw std::logic_error("The method or operation is not implemented.");
}
void GnmCommandBufferDraw::popMarker()
{
//throw std::logic_error("The method or operation is not implemented.");
// throw std::logic_error("The method or operation is not implemented.");
}
void GnmCommandBufferDraw::applyRenderState()
{
if (m_flags.test(GnmContextFlag::DirtyRasterizerState))
{
applyRasterizerState();
}
}
void GnmCommandBufferDraw::applyInputLayout()
{
}
void GnmCommandBufferDraw::applyPrimitiveTopology()
{
}
void GnmCommandBufferDraw::applyBlendState()
{
}
void GnmCommandBufferDraw::applyBlendFactor()
{
}
void GnmCommandBufferDraw::applyDepthStencilState()
{
}
void GnmCommandBufferDraw::applyStencilRef()
{
}
void GnmCommandBufferDraw::applyRasterizerState()
{
m_context->setRasterizerState(
m_state.gp.rs.state);
m_flags.clr(GnmContextFlag::DirtyRasterizerState);
}
void GnmCommandBufferDraw::applyViewportState()
{
}
void GnmCommandBufferDraw::initDefaultRenderState()
{
m_state.gp.sc = {};
m_state.gp.ia.indexBuffer = nullptr;
m_state.gp.ia.indexType = VK_INDEX_TYPE_UINT16;
initDefaultPrimitiveTopology(&m_state.gp.ia.isState);
m_state.gp.rs = {};
initDefaultRasterizerState(&m_state.gp.rs.state);
m_state.gp.om = {};
initDefaultDepthStencilState(&m_state.gp.om.dsState);
VltBlendMode cbState;
initDefaultBlendState(&cbState,
&m_state.gp.om.loState,
&m_state.gp.om.msState);
std::fill(m_state.gp.om.blendModes.begin(),
m_state.gp.om.blendModes.end(),
cbState);
m_state.cp.sc = {};
}
void GnmCommandBufferDraw::initDefaultPrimitiveTopology(
VltInputAssemblyState* iaState)
{
iaState->primitiveTopology = VK_PRIMITIVE_TOPOLOGY_MAX_ENUM;
iaState->primitiveRestart = VK_FALSE;
iaState->patchVertexCount = 0;
}
void GnmCommandBufferDraw::initDefaultRasterizerState(
VltRasterizerState* rsState)
{
rsState->polygonMode = VK_POLYGON_MODE_FILL;
rsState->cullMode = VK_CULL_MODE_BACK_BIT;
rsState->frontFace = VK_FRONT_FACE_CLOCKWISE;
rsState->depthClipEnable = VK_TRUE;
rsState->depthBiasEnable = VK_FALSE;
rsState->sampleCount = VK_SAMPLE_COUNT_1_BIT;
rsState->conservativeMode = VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT;
}
void GnmCommandBufferDraw::initDefaultDepthStencilState(
VltDepthStencilState* dsState)
{
VkStencilOpState stencilOp;
stencilOp.failOp = VK_STENCIL_OP_KEEP;
stencilOp.passOp = VK_STENCIL_OP_KEEP;
stencilOp.depthFailOp = VK_STENCIL_OP_KEEP;
stencilOp.compareOp = VK_COMPARE_OP_ALWAYS;
stencilOp.compareMask = 255;
stencilOp.writeMask = 255;
stencilOp.reference = 0;
dsState->enableDepthTest = VK_TRUE;
dsState->enableDepthWrite = VK_TRUE;
dsState->enableStencilTest = VK_FALSE;
dsState->depthCompareOp = VK_COMPARE_OP_LESS;
dsState->stencilOpFront = stencilOp;
dsState->stencilOpBack = stencilOp;
}
void GnmCommandBufferDraw::initDefaultBlendState(
VltBlendMode* cbState,
VltLogicOpState* loState,
VltMultisampleState* msState)
{
cbState->enableBlending = VK_FALSE;
cbState->colorSrcFactor = VK_BLEND_FACTOR_ONE;
cbState->colorDstFactor = VK_BLEND_FACTOR_ZERO;
cbState->colorBlendOp = VK_BLEND_OP_ADD;
cbState->alphaSrcFactor = VK_BLEND_FACTOR_ONE;
cbState->alphaDstFactor = VK_BLEND_FACTOR_ZERO;
cbState->alphaBlendOp = VK_BLEND_OP_ADD;
cbState->writeMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
loState->enableLogicOp = VK_FALSE;
loState->logicOp = VK_LOGIC_OP_NO_OP;
msState->sampleMask = 0xFFFFFFFF;
msState->enableAlphaToCoverage = VK_FALSE;
}
} // namespace sce::Gnm

View file

@ -5,14 +5,11 @@
#include "GnmRenderState.h"
#include "Gcn/GcnShaderBinary.h"
namespace sce::gcn
{
class GcnModule;
} // namespace sce::gcn
#include "Violet/VltContextState.h"
namespace sce::Gnm
{
class GnmShader;
// This class is designed for graphics development,
// no reverse engineering knowledge should be required.
// It's responsible for mapping Gnm input/structures to Violet input/structures,
@ -157,11 +154,10 @@ namespace sce::Gnm
virtual void popMarker() override;
private:
private:
const void* findFetchShader(
const gcn::GcnShaderResourceTable& table,
const UserDataArray& userData);
const UserDataSlot& userData);
bool isSingleVertexBinding(
const uint32_t* vtxTable,
@ -177,8 +173,7 @@ namespace sce::Gnm
inline void bindVertexBuffer(
const Buffer* vsharp, uint32_t binding);
void updateVertexBinding(gcn::GcnModule& vsModule);
void updateVertexBinding(GnmShader& vsModule);
void updateVertexShaderStage();
void updatePixelShaderStage();
@ -199,9 +194,41 @@ namespace sce::Gnm
bool isDepth,
const Texture* tsharp) override;
void applyRenderState();
void applyInputLayout();
void applyPrimitiveTopology();
void applyBlendState();
void applyBlendFactor();
void applyDepthStencilState();
void applyStencilRef();
void applyRasterizerState();
void applyViewportState();
void initDefaultRenderState();
static void initDefaultPrimitiveTopology(
vlt::VltInputAssemblyState* iaState);
static void initDefaultRasterizerState(
vlt::VltRasterizerState* rsState);
static void initDefaultDepthStencilState(
vlt::VltDepthStencilState* dsState);
static void initDefaultBlendState(
vlt::VltBlendMode* cbState,
vlt::VltLogicOpState* loState,
vlt::VltMultisampleState* msState);
private:
GnmGraphicsState m_state;
GnmContextFlags m_flags;
};
} // namespace sce::Gnm

View file

@ -1,26 +1,23 @@
#include "SceLabelManager.h"
#include "Gnm/GnmGpuLabel.h"
#include "GnmLabelManager.h"
#include "GnmGpuLabel.h"
#include "Violet/VltDevice.h"
#include <mutex>
LOG_CHANNEL(Graphic.Gnm.SceLabelManager);
namespace sce
namespace sce::Gnm
{
using namespace Gnm;
SceLabelManager::SceLabelManager(vlt::VltDevice* device) :
GnmLabelManager::GnmLabelManager(vlt::VltDevice* device) :
m_device(device)
{
}
SceLabelManager::~SceLabelManager()
GnmLabelManager::~GnmLabelManager()
{
}
GnmGpuLabel* SceLabelManager::getLabel(void* labelAddress)
GnmGpuLabel* GnmLabelManager::getLabel(void* labelAddress)
{
LOG_ASSERT(labelAddress != nullptr, "null label address passed.");
@ -42,7 +39,7 @@ namespace sce
return label;
}
void SceLabelManager::reset()
void GnmLabelManager::reset()
{
std::lock_guard<util::sync::Spinlock> guard(m_lock);
m_labels.clear();

View file

@ -1,29 +1,26 @@
#pragma once
#include "SceCommon.h"
#include "GnmCommon.h"
#include "UtilSync.h"
#include <unordered_map>
namespace sce
namespace sce::vlt
{
namespace vlt
{
class VltDevice;
} // namespace vlt
class VltDevice;
} // namespace vlt
namespace Gnm
{
class GnmGpuLabel;
} // namespace Gnm
namespace sce::Gnm
{
class GnmGpuLabel;
class SceLabelManager
class GnmLabelManager
{
public:
SceLabelManager(vlt::VltDevice* device);
~SceLabelManager();
GnmLabelManager(vlt::VltDevice* device);
~GnmLabelManager();
Gnm::GnmGpuLabel* getLabel(void* labelAddress);
GnmGpuLabel* getLabel(void* labelAddress);
void reset();

View file

@ -2,13 +2,15 @@
#include "GnmCommon.h"
#include "GnmConstant.h"
#include "GnmStructure.h"
#include "GnmLimits.h"
#include "GnmStructure.h"
#include "UtilFlag.h"
#include "Gcn/GcnConstants.h"
#include "Gcn/GcnShaderMeta.h"
#include "Gcn/GcnModule.h"
#include "Gcn/GcnShaderMeta.h"
#include "Violet/VltConstantState.h"
#include "Violet/VltRenderTarget.h"
#include <array>
@ -26,54 +28,54 @@ namespace sce
namespace sce::Gnm
{
/**
* \brief Graphics pipeline state flags
*
* Stores some information on which state
* of the graphics and compute pipelines
* has changed and/or needs to be updated.
*/
* \brief Graphics pipeline state flags
*
* Stores some information on which state
* of the graphics and compute pipelines
* has changed and/or needs to be updated.
*/
enum class GnmContextFlag : uint32_t
{
GpPlaceHolder, ///< PlaceHolder
DirtyViewportScissor,
DirtyRasterizerState,
DirtyRenderTargets,
DirtyBlendState,
};
using GnmContextFlags = util::Flags<GnmContextFlag>;
using UserDataSlot = std::array<uint32_t, gcn::kMaxUserDataCount>;
using UserDataArray = std::array<uint32_t, gcn::kMaxUserDataCount>;
struct GnmShaderContext
{
const void* code = nullptr;
UserDataArray userData = {};
gcn::GcnShaderMeta meta = {};
UserDataSlot userData = {};
gcn::GcnShaderMeta meta;
};
struct GnmInputAssemblerState
{
vlt::Rc<vlt::VltBuffer> indexBuffer = nullptr;
VkIndexType indexType = VK_INDEX_TYPE_UINT32;
VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_MAX_ENUM;
vlt::Rc<vlt::VltBuffer> indexBuffer = nullptr;
VkIndexType indexType = VK_INDEX_TYPE_UINT32;
vlt::VltInputAssemblyState isState;
};
struct GnmRasterizerState
{
uint32_t numViewports = 0;
uint32_t numScissors = 0;
VkRect2D scissor;
std::array<VkViewport, MaxNumViewports> viewports;
std::array<VkRect2D, MaxNumViewports> scissors;
VltRasterizerState state;
vlt::VltRasterizerState state;
};
struct GnmOutputMergerState
{
std::array<vlt::Rc<VltImageView>, MaxNumRenderTargets> renderTargetViews;
vlt::Rc<VltImageView> depthStencilView;
vlt::VltRenderTargets renderTargets;
vlt::VltDepthStencilState dsState;
vlt::VltMultisampleState msState;
vlt::VltLogicOpState loState;
std::array<VltBlendMode, 8> blendModes;
VltDepthStencilState dsState;
VltMultisampleState msState;
VltLogicOpState loState;
float blendFactor[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
uint32_t sampleMask = 0xFFFFFFFFu;

View file

@ -27,6 +27,8 @@ namespace sce::Gnm
GcnModule module(
reinterpret_cast<const uint8_t*>(code));
m_resources = module.getResourceTable();
m_shader = module.compile(meta, *moduleInfo);
m_shader->setShaderKey(*key);
}
@ -43,7 +45,7 @@ namespace sce::Gnm
{
}
GnmShader GcnShaderModuleSet::GetShaderModule(const VltShaderKey* key,
GnmShader GcnShaderModuleSet::getShaderModule(const VltShaderKey* key,
const GcnModuleInfo* moduleInfo,
const GcnShaderMeta& meta,
const void* code)

View file

@ -2,20 +2,19 @@
#include "GnmCommon.h"
#include "Gcn/GcnModInfo.h"
#include "Violet/VltHash.h"
#include "Gcn/GcnHeader.h"
#include "Gcn/GcnShaderMeta.h"
#include "Violet/VltShaderKey.h"
#include <array>
#include <mutex>
#include <unordered_map>
namespace sce::vlt
{
class VltShaderKey;
class VltShader;
} // namespace sce::vlt
namespace sce::gcn
{
union GcnShaderMeta;
} // namespace sce::vlt
namespace sce::Gnm
{
@ -32,17 +31,23 @@ namespace sce::Gnm
GnmShader();
GnmShader(const vlt::VltShaderKey* key,
const gcn::GcnModuleInfo* moduleInfo,
const GcnShaderMeta& meta,
const gcn::GcnShaderMeta& meta,
const void* code);
~GnmShader();
vlt::Rc<VltShader> getShader() const
vlt::Rc<vlt::VltShader> getShader() const
{
return m_shader;
}
const gcn::GcnShaderResourceTable& getResources() const
{
return m_resources;
}
private:
vlt::Rc<vlt::VltShader> m_shader;
vlt::Rc<vlt::VltShader> m_shader;
gcn::GcnShaderResourceTable m_resources;
};
/**
@ -60,10 +65,10 @@ namespace sce::Gnm
GcnShaderModuleSet();
~GcnShaderModuleSet();
GnmShader GetShaderModule(
GnmShader getShaderModule(
const vlt::VltShaderKey* key,
const gcn::GcnModuleInfo* moduleInfo,
const GcnShaderMeta& meta,
const gcn::GcnShaderMeta& meta,
const void* code);
private:

View file

@ -963,34 +963,6 @@ namespace sce::vlt
}
}
void VltContext::setDepthClearValue(VkClearValue clearValue)
{
this->updateFramebuffer();
m_state.cb.clearValues.depthValue.depthStencil.depth = clearValue.depthStencil.depth;
// TODO:
// The way for Gnm to clear a depth target is to render a fullscreen
// quad while setting DeRenderControl to enable depth clear.
// Vulkan don't have DeRenderControl, we need to find an alternative way.
m_state.cb.attachmentOps.depthOps.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
m_state.cb.attachmentOps.depthOps.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
m_flags.set(VltContextFlag::GpDirtyFramebufferState);
}
void VltContext::setStencilClearValue(VkClearValue clearValue)
{
this->updateFramebuffer();
m_state.cb.clearValues.depthValue.depthStencil.stencil = clearValue.depthStencil.stencil;
m_state.cb.attachmentOps.depthOps.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
m_state.cb.attachmentOps.depthOps.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
m_flags.set(VltContextFlag::GpDirtyFramebufferState);
}
void VltContext::emitRenderTargetReadbackBarrier()
{
emitMemoryBarrier(VK_DEPENDENCY_BY_REGION_BIT,

View file

@ -338,27 +338,6 @@ namespace sce::vlt
VkImageAspectFlags clearAspects,
VkClearValue clearValue);
/**
* \brief Set depth clear value
*
* Performed at render pass begin
*
* \param [in] clearValue The clear value
*/
void setDepthClearValue(
VkClearValue clearValue);
/**
* \brief Set stencil clear value
*
* Performed at render pass begin
*
* \param [in] clearValue The clear value
*/
void setStencilClearValue(
VkClearValue clearValue);
/**
* \brief Emits barrier for render target
*/

View file

@ -166,10 +166,9 @@ namespace sce::vlt
// Do not fix binding id if we read from a external binary file.
m_idOffsets.clear();
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();
auto code = m_code.decompress();
m_key = VltShaderKey(m_stage, GcnShaderKey(0, 0));
m_hash = m_key.hash();
}
void VltShader::eliminateInput(SpirvCodeBuffer& code, uint32_t location)

View file

@ -12,12 +12,12 @@ namespace sce
namespace Gnm
{
enum GpuMode;
class GnmLabelManager;
} // namespace Gnm
class SceVideoOut;
class SceGnmDriver;
class SceResourceTracker;
class SceLabelManager;
class VirtualGPU final
{
@ -57,7 +57,7 @@ namespace sce
/**
* \brief Get GPU label manager.
*/
SceLabelManager& labelManager();
Gnm::GnmLabelManager& labelManager();
/**
* \brief Global GPU mode.
@ -79,8 +79,8 @@ namespace sce
std::shared_ptr<SceGnmDriver> m_gnmDriver = nullptr;
std::shared_ptr<SceResourceTracker> m_tracker = nullptr;
std::shared_ptr<SceLabelManager> m_labelManager = nullptr;
std::shared_ptr<SceResourceTracker> m_tracker = nullptr;
std::shared_ptr<Gnm::GnmLabelManager> m_labelManager = nullptr;
};
} // namespace sce