Commit af4ed53d by Chris Forbes

Initial stub implementation of SpirvShader

This will eventually replace Shader and related subclasses. The interesting bit here is the instruction iterator, which allows fairly safe access to the instruction stream without needing the rest of the code to care too much about the physical layout. Bug: b/120799499 Change-Id: Id0d94c4b807ddb1e4325de147ca1f651171779b7 Reviewed-on: https://swiftshader-review.googlesource.com/c/23049Reviewed-by: 's avatarCorentin Wallez <cwallez@google.com> Reviewed-by: 's avatarAlexis Hétu <sugoi@google.com> Tested-by: 's avatarChris Forbes <chrisforbes@google.com>
parent 57378335
// Copyright 2018 The SwiftShader Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <spirv/unified1/spirv.hpp>
#include "SpirvShader.hpp"
#include "System/Math.hpp"
#include "System/Debug.hpp"
#include "Device/Config.hpp"
namespace sw
{
volatile int SpirvShader::serialCounter = 1; // Start at 1, 0 is invalid shader.
SpirvShader::SpirvShader(InsnStore const &insns) : insns{insns}, serialID{serialCounter++}, modes{}
{
// Simplifying assumptions (to be satisfied by earlier transformations)
// - There is exactly one extrypoint in the module, and it's the one we want
// - Input / Output interface blocks, builtin or otherwise, have been split.
// - The only input/output OpVariables present are those used by the entrypoint
for (auto insn : *this) {
switch (insn.opcode()) {
case spv::OpExecutionMode:
ProcessExecutionMode(insn);
break;
default:
break; // This is OK, these passes are intentionally partial
}
}
}
void SpirvShader::ProcessExecutionMode(InsnIterator insn)
{
auto mode = static_cast<spv::ExecutionMode>(insn.word(2));
switch (mode) {
case spv::ExecutionModeEarlyFragmentTests:
modes.EarlyFragmentTests = true;
break;
case spv::ExecutionModeDepthReplacing:
modes.DepthReplacing = true;
break;
case spv::ExecutionModeDepthGreater:
modes.DepthGreater = true;
break;
case spv::ExecutionModeDepthLess:
modes.DepthLess = true;
break;
case spv::ExecutionModeDepthUnchanged:
modes.DepthUnchanged = true;
break;
case spv::ExecutionModeLocalSize:
modes.LocalSizeX = insn.word(3);
modes.LocalSizeZ = insn.word(5);
modes.LocalSizeY = insn.word(4);
break;
case spv::ExecutionModeOriginUpperLeft:
// This is always the case for a Vulkan shader. Do nothing.
break;
default:
UNIMPLEMENTED("No other execution modes are permitted");
}
}
}
\ No newline at end of file
// Copyright 2018 The SwiftShader Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef sw_SpirvShader_hpp
#define sw_SpirvShader_hpp
#include "System/Types.hpp"
#include "Vulkan/VkDebug.hpp"
#include <string>
#include <vector>
#include <unordered_map>
#include <cstdint>
#include <spirv/unified1/spirv.hpp>
namespace sw
{
class SpirvShader
{
public:
using InsnStore = std::vector<uint32_t>;
InsnStore insns;
/* Pseudo-iterator over SPIRV instructions, designed to support range-based-for. */
class InsnIterator
{
InsnStore::const_iterator iter;
public:
spv::Op opcode() const
{
return static_cast<spv::Op>(*iter & spv::OpCodeMask);
}
uint32_t wordCount() const
{ return *iter >> spv::WordCountShift; }
uint32_t word(uint32_t n) const
{
ASSERT(n < wordCount());
return iter[n];
}
bool operator!=(InsnIterator const &other) const
{
return iter != other.iter;
}
InsnIterator operator*() const
{ return *this; }
InsnIterator &operator++()
{
iter += wordCount();
return *this;
}
InsnIterator const operator++(int)
{
InsnIterator ret{*this};
iter += wordCount();
return ret;
}
InsnIterator(InsnIterator const &other) = default;
InsnIterator() = default;
explicit InsnIterator(InsnStore::const_iterator iter) : iter{iter}
{}
};
/* range-based-for interface */
InsnIterator begin() const
{ return InsnIterator{insns.cbegin() + 5}; }
InsnIterator end() const
{ return InsnIterator{insns.cend()}; }
int getSerialID() const
{ return serialID; }
explicit SpirvShader(InsnStore const &insns);
struct Modes
{
bool EarlyFragmentTests : 1;
bool DepthReplacing : 1;
bool DepthGreater : 1;
bool DepthLess : 1;
bool DepthUnchanged : 1;
// Compute workgroup dimensions
int LocalSizeX, LocalSizeY, LocalSizeZ;
};
Modes const &getModes() const
{ return modes; }
private:
const int serialID;
static volatile int serialCounter;
Modes modes;
void ProcessExecutionMode(InsnIterator it);
};
}
#endif // sw_SpirvShader_hpp
\ No newline at end of file
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include <Pipeline/SpirvShader.hpp>
#include "VkPipeline.hpp" #include "VkPipeline.hpp"
#include "VkShaderModule.hpp" #include "VkShaderModule.hpp"
...@@ -370,6 +371,8 @@ GraphicsPipeline::GraphicsPipeline(const VkGraphicsPipelineCreateInfo* pCreateIn ...@@ -370,6 +371,8 @@ GraphicsPipeline::GraphicsPipeline(const VkGraphicsPipelineCreateInfo* pCreateIn
void GraphicsPipeline::destroyPipeline(const VkAllocationCallbacks* pAllocator) void GraphicsPipeline::destroyPipeline(const VkAllocationCallbacks* pAllocator)
{ {
delete vertexShader;
delete fragmentShader;
} }
size_t GraphicsPipeline::ComputeRequiredAllocationSize(const VkGraphicsPipelineCreateInfo* pCreateInfo) size_t GraphicsPipeline::ComputeRequiredAllocationSize(const VkGraphicsPipelineCreateInfo* pCreateInfo)
...@@ -379,8 +382,30 @@ size_t GraphicsPipeline::ComputeRequiredAllocationSize(const VkGraphicsPipelineC ...@@ -379,8 +382,30 @@ size_t GraphicsPipeline::ComputeRequiredAllocationSize(const VkGraphicsPipelineC
void GraphicsPipeline::compileShaders(const VkAllocationCallbacks* pAllocator, const VkGraphicsPipelineCreateInfo* pCreateInfo) void GraphicsPipeline::compileShaders(const VkAllocationCallbacks* pAllocator, const VkGraphicsPipelineCreateInfo* pCreateInfo)
{ {
vertexRoutine = Cast(pCreateInfo->pStages[0].module)->compile(pAllocator); for (auto pStage = pCreateInfo->pStages; pStage != pCreateInfo->pStages + pCreateInfo->stageCount; pStage++) {
fragmentRoutine = Cast(pCreateInfo->pStages[1].module)->compile(pAllocator); auto module = Cast(pStage->module);
// TODO: apply prep passes using SPIRV-Opt here.
// - Apply and freeze specializations, etc.
auto code = module->getCode();
// TODO: pass in additional information here:
// - any NOS from pCreateInfo which we'll actually need
auto spirvShader = new sw::SpirvShader{code};
switch (pStage->stage) {
case VK_SHADER_STAGE_VERTEX_BIT:
vertexShader = spirvShader;
break;
case VK_SHADER_STAGE_FRAGMENT_BIT:
fragmentShader = spirvShader;
break;
default:
UNIMPLEMENTED("Unsupported stage");
}
}
} }
uint32_t GraphicsPipeline::computePrimitiveCount(uint32_t vertexCount) const uint32_t GraphicsPipeline::computePrimitiveCount(uint32_t vertexCount) const
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
#include "VkObject.hpp" #include "VkObject.hpp"
#include "Device/Renderer.hpp" #include "Device/Renderer.hpp"
namespace sw { class SpirvShader; }
namespace vk namespace vk
{ {
...@@ -65,8 +67,12 @@ public: ...@@ -65,8 +67,12 @@ public:
const sw::Color<float>& getBlendConstants() const; const sw::Color<float>& getBlendConstants() const;
private: private:
sw::SpirvShader *vertexShader = nullptr;
sw::SpirvShader *fragmentShader = nullptr;
rr::Routine* vertexRoutine; rr::Routine* vertexRoutine;
rr::Routine* fragmentRoutine; rr::Routine* fragmentRoutine;
sw::Context context; sw::Context context;
sw::Rect scissor; sw::Rect scissor;
VkViewport viewport; VkViewport viewport;
......
...@@ -22,6 +22,7 @@ namespace vk ...@@ -22,6 +22,7 @@ namespace vk
ShaderModule::ShaderModule(const VkShaderModuleCreateInfo* pCreateInfo, void* mem) : code(reinterpret_cast<uint32_t*>(mem)) ShaderModule::ShaderModule(const VkShaderModuleCreateInfo* pCreateInfo, void* mem) : code(reinterpret_cast<uint32_t*>(mem))
{ {
memcpy(code, pCreateInfo->pCode, pCreateInfo->codeSize); memcpy(code, pCreateInfo->pCode, pCreateInfo->codeSize);
wordCount = static_cast<uint32_t>(pCreateInfo->codeSize / sizeof(uint32_t));
} }
void ShaderModule::destroy(const VkAllocationCallbacks* pAllocator) void ShaderModule::destroy(const VkAllocationCallbacks* pAllocator)
...@@ -34,10 +35,4 @@ size_t ShaderModule::ComputeRequiredAllocationSize(const VkShaderModuleCreateInf ...@@ -34,10 +35,4 @@ size_t ShaderModule::ComputeRequiredAllocationSize(const VkShaderModuleCreateInf
return pCreateInfo->codeSize; return pCreateInfo->codeSize;
} }
rr::Routine* ShaderModule::compile(const VkAllocationCallbacks* pAllocator)
{
// FIXME: Compile the code here
return nullptr;
}
} // namespace vk } // namespace vk
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#define VK_SHADER_MODULE_HPP_ #define VK_SHADER_MODULE_HPP_
#include "VkObject.hpp" #include "VkObject.hpp"
#include <vector>
namespace rr namespace rr
{ {
...@@ -32,12 +33,14 @@ public: ...@@ -32,12 +33,14 @@ public:
~ShaderModule() = delete; ~ShaderModule() = delete;
void destroy(const VkAllocationCallbacks* pAllocator); void destroy(const VkAllocationCallbacks* pAllocator);
rr::Routine* compile(const VkAllocationCallbacks* pAllocator);
static size_t ComputeRequiredAllocationSize(const VkShaderModuleCreateInfo* pCreateInfo); static size_t ComputeRequiredAllocationSize(const VkShaderModuleCreateInfo* pCreateInfo);
// TODO: reconsider boundary of ShaderModule class; try to avoid 'expose the
// guts' operations, and this copy.
std::vector<uint32_t> getCode() const { return std::vector<uint32_t>{ code, code + wordCount };}
private: private:
uint32_t* code = nullptr; uint32_t* code = nullptr;
uint32_t wordCount = 0;
}; };
static inline ShaderModule* Cast(VkShaderModule object) static inline ShaderModule* Cast(VkShaderModule object)
......
...@@ -145,6 +145,7 @@ copy "$(OutDir)vk_swiftshader.dll" "$(SolutionDir)out\$(Configuration)_$(Platfor ...@@ -145,6 +145,7 @@ copy "$(OutDir)vk_swiftshader.dll" "$(SolutionDir)out\$(Configuration)_$(Platfor
<ClCompile Include="..\Pipeline\SetupRoutine.cpp" /> <ClCompile Include="..\Pipeline\SetupRoutine.cpp" />
<ClCompile Include="..\Pipeline\Shader.cpp" /> <ClCompile Include="..\Pipeline\Shader.cpp" />
<ClCompile Include="..\Pipeline\ShaderCore.cpp" /> <ClCompile Include="..\Pipeline\ShaderCore.cpp" />
<ClCompile Include="..\Pipeline\SpirvShader.cpp" />
<ClCompile Include="..\Pipeline\VertexProgram.cpp" /> <ClCompile Include="..\Pipeline\VertexProgram.cpp" />
<ClCompile Include="..\Pipeline\VertexRoutine.cpp" /> <ClCompile Include="..\Pipeline\VertexRoutine.cpp" />
<ClCompile Include="..\Pipeline\VertexShader.cpp" /> <ClCompile Include="..\Pipeline\VertexShader.cpp" />
...@@ -251,6 +252,7 @@ copy "$(OutDir)vk_swiftshader.dll" "$(SolutionDir)out\$(Configuration)_$(Platfor ...@@ -251,6 +252,7 @@ copy "$(OutDir)vk_swiftshader.dll" "$(SolutionDir)out\$(Configuration)_$(Platfor
<ClInclude Include="..\Pipeline\SetupRoutine.hpp" /> <ClInclude Include="..\Pipeline\SetupRoutine.hpp" />
<ClInclude Include="..\Pipeline\Shader.hpp" /> <ClInclude Include="..\Pipeline\Shader.hpp" />
<ClInclude Include="..\Pipeline\ShaderCore.hpp" /> <ClInclude Include="..\Pipeline\ShaderCore.hpp" />
<ClInclude Include="..\Pipeline\SpirvShader.hpp" />
<ClInclude Include="..\Pipeline\VertexPipeline.hpp" /> <ClInclude Include="..\Pipeline\VertexPipeline.hpp" />
<ClInclude Include="..\Pipeline\VertexProgram.hpp" /> <ClInclude Include="..\Pipeline\VertexProgram.hpp" />
<ClInclude Include="..\Pipeline\VertexRoutine.hpp" /> <ClInclude Include="..\Pipeline\VertexRoutine.hpp" />
...@@ -319,4 +321,4 @@ copy "$(OutDir)vk_swiftshader.dll" "$(SolutionDir)out\$(Configuration)_$(Platfor ...@@ -319,4 +321,4 @@ copy "$(OutDir)vk_swiftshader.dll" "$(SolutionDir)out\$(Configuration)_$(Platfor
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
</ImportGroup> </ImportGroup>
</Project> </Project>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment