diff options
| author | Tim Foley <tfoleyNV@users.noreply.github.com> | 2018-08-03 08:39:28 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-08-03 08:39:28 -0700 |
| commit | 68d705f6c805c9b4d31b386e065762e6db13ad18 (patch) | |
| tree | 97ffc0f24358101222d1bc62ac0c50affc55af12 /tools/gfx/render.h | |
| parent | 5ea746a571ced32a8975eb3a238c562b3d487149 (diff) | |
Major overhaul of Renderer abstraction, to support a new example (#624)
The original goal here was to bring up a second example program: `model-viewer`.
While the existing `hello-world` example is enough to get somebody up to speed with the basics of the Slang API (as a drop-in replacement for `D3DCompile` or similar), it doesn't really show any of the big-picture stuff that Slang is meant to enable.
There wasn't any use of D3D12/Vulkan descriptor tables/sets, and there wasn't any use of interfaces, generics, or `ParameterBlock`s in the shader code.
The `model-viewer` example addresses these issues. Its shader code involves generics, interfaces, and multiple `ParameterBlock`s, and the host-side code demonstrates a few key things for working with Slang:
* There is an application-level abstraction for parameter blocks, that combines the graphics-API descriptor set object with Slang type information
* There is a shader cache layer used to look up an appropriate variant of a rendering effect by using parameter block types to "plug in" global type variables
* There is a clear separation between the phases of compilation: a first phase that does semantic checking and enables reflection-based allocation of graphics API objects, followed by one or more code generation passes for specialized kernels.
This example is certainly not perfect, and it will need to be revamped more going forward. In particular:
* The output picture is ugly as sin. We need a plan for how to get this to load better content, perhaps even popping up an error message to note that the required input data isn't present in the basic repository.
* The shader code is too simplistic. There isn't any real material variety, and the `IMaterial` abstraction is completely wrong.
* The use of parameter blocks is facile because there are no resource parameters right now. Fixing that will likely expose issues around interfacing with Slang's reflection API.
* The whole example exposes the issue that Slang's current APIs aren't really designed for the benefit of two-phase compilation (since our many client application has been stuck on one-phase compilation).
* Global type parameters are actually a Bad Idea that we only did for compatibility with existing codebases. We should not be showing them off in an example of the Right Way to use Slang, but the language support for type parameters on entry points is still not complete.
Of course, the majority of the changes here are *not* inside the example applications, and instead involve a major overhaul of the `Renderer` abstraction that is used for both tests and examples. The main thrust of the change is to make the abstraction layer be closer to the D3D12/Vulkan model than to a D3D11-style model. This is important for the `model-viewer` example, since it aspires to show how Slang can be incorporated into a renderer that targets a modern API. The most important bit is actually the use of descriptor sets and "pipeline layouts" a la Vulkan, since without these Slang's `ParameterBlock` abstraction won't make a lot of sense.
Implementation of the abstraction for the various APIs has very much been on an as-needed basis. The current implementation is just enough for the two examples to work, plus enough to get all the tests to pass in both debug and release builds on Windows.
A big missing feature in the API abstraction right now is memory lifetime management. The code had been trending toward something D3D11-like where a constant buffer could be mapped per-frame with the implementation doing behind-the-scenes allocation for targets like D3D12/Vulkan. I'd like to shift more toward a model of just exposing "transient" allocations that are only valid for one frame, because these are more representation of how an efficient renderer for next-generation APIs will work. That transition isn't actually complete, though, so there are problems with the existing examples where `hello-world` is actually scribbling into memory that the GPU might still be using, while `model-viewer` is doing full-on heavy-weight allocations on a per-frame basis with no real concern for the performance implications.
All together, there are a lot of things here that need more work, but this branch has been way too long-lived already, and so I'd like to get this checked in as long as all the tests pass.
Diffstat (limited to 'tools/gfx/render.h')
| -rw-r--r-- | tools/gfx/render.h | 869 |
1 files changed, 869 insertions, 0 deletions
diff --git a/tools/gfx/render.h b/tools/gfx/render.h new file mode 100644 index 000000000..b43152b68 --- /dev/null +++ b/tools/gfx/render.h @@ -0,0 +1,869 @@ +// render.h +#pragma once + +#include "window.h" + +//#include "shader-input-layout.h" + +#include "../../slang-com-helper.h" + +#include "../../source/core/smart-pointer.h" +#include "../../source/core/list.h" +#include "../../source/core/dictionary.h" + +namespace gfx { + +using Slang::RefObject; +using Slang::RefPtr; +using Slang::Dictionary; +using Slang::GetHashCode; +using Slang::combineHash; +using Slang::List; + +typedef SlangResult Result; + +// Had to move here, because Options needs types defined here +typedef intptr_t Int; +typedef uintptr_t UInt; + +// pre declare types +class Surface; + +// Declare opaque type +class InputLayout: public Slang::RefObject +{ + public: +}; + +enum class PipelineType +{ + Unknown, + Graphics, + Compute, + CountOf, +}; + +enum class StageType +{ + Unknown, + Vertex, + Hull, + Domain, + Geometry, + Fragment, + Compute, + CountOf, +}; + +enum class RendererType +{ + Unknown, + DirectX11, + DirectX12, + OpenGl, + Vulkan, + CountOf, +}; + +enum class ProjectionStyle +{ + Unknown, + OpenGl, + DirectX, + Vulkan, + CountOf, +}; + +/// The style of the binding +enum class BindingStyle +{ + Unknown, + DirectX, + OpenGl, + Vulkan, + CountOf, +}; + +class ShaderProgram: public Slang::RefObject +{ +public: + + struct KernelDesc + { + StageType stage; + void const* codeBegin; + void const* codeEnd; + + UInt getCodeSize() const { return (char const*)codeEnd - (char const*)codeBegin; } + }; + + struct Desc + { + PipelineType pipelineType; + KernelDesc const* kernels; + Int kernelCount; + + /// Find and return the kernel for `stage`, if present. + KernelDesc const* findKernel(StageType stage) const + { + for(Int ii = 0; ii < kernelCount; ++ii) + if(kernels[ii].stage == stage) + return &kernels[ii]; + return nullptr; + } + }; +}; + +struct ShaderCompileRequest +{ + struct SourceInfo + { + char const* path; + + // The data may either be source text (in which + // case it can be assumed to be nul-terminated with + // `dataEnd` pointing at the terminator), or + // raw binary data (in which case `dataEnd` points + // at the end of the buffer). + char const* dataBegin; + char const* dataEnd; + }; + + struct EntryPoint + { + char const* name = nullptr; + SourceInfo source; + }; + + SourceInfo source; + EntryPoint vertexShader; + EntryPoint fragmentShader; + EntryPoint computeShader; + Slang::List<Slang::String> entryPointTypeArguments; +}; + +/// Different formats of things like pixels or elements of vertices +/// NOTE! Any change to this type (adding, removing, changing order) - must also be reflected in changes to RendererUtil +enum class Format +{ + Unknown, + + RGBA_Float32, + RGB_Float32, + RG_Float32, + R_Float32, + + RGBA_Unorm_UInt8, + + R_UInt32, + + D_Float32, + D_Unorm24_S8, + + CountOf, +}; + +struct InputElementDesc +{ + char const* semanticName; + UInt semanticIndex; + Format format; + UInt offset; +}; + +enum class MapFlavor +{ + Unknown, ///< Unknown mapping type + HostRead, + HostWrite, + WriteDiscard, +}; + +enum class PrimitiveTopology +{ + TriangleList, +}; + +class Resource: public Slang::RefObject +{ + public: + + /// The type of resource. + /// NOTE! The order needs to be such that all texture types are at or after Texture1D (otherwise isTexture won't work correctly) + enum class Type + { + Unknown, ///< Unknown + Buffer, ///< A buffer (like a constant/index/vertex buffer) + Texture1D, ///< A 1d texture + Texture2D, ///< A 2d texture + Texture3D, ///< A 3d texture + TextureCube, ///< A cubemap consists of 6 Texture2D like faces + CountOf, + }; + + /// Describes how a resource is to be used + enum class Usage + { + Unknown = -1, + VertexBuffer = 0, + IndexBuffer, + ConstantBuffer, + StreamOutput, + RenderTarget, + DepthRead, + DepthWrite, + UnorderedAccess, + PixelShaderResource, + NonPixelShaderResource, + GenericRead, + CountOf, + }; + + /// Binding flags describe all of the ways a resource can be bound - and therefore used + struct BindFlag + { + enum Enum + { + VertexBuffer = 0x001, + IndexBuffer = 0x002, + ConstantBuffer = 0x004, + StreamOutput = 0x008, + RenderTarget = 0x010, + DepthStencil = 0x020, + UnorderedAccess = 0x040, + PixelShaderResource = 0x080, + NonPixelShaderResource = 0x100, + }; + }; + + /// Combinations describe how a resource can be accessed (typically by the host/cpu) + struct AccessFlag + { + enum Enum + { + Read = 0x1, + Write = 0x2 + }; + }; + + /// Base class for Descs + struct DescBase + { + bool canBind(BindFlag::Enum bindFlag) const { return (bindFlags & bindFlag) != 0; } + bool hasCpuAccessFlag(AccessFlag::Enum accessFlag) { return (cpuAccessFlags & accessFlag) != 0; } + + Type type = Type::Unknown; + + int bindFlags = 0; ///< Combination of Resource::BindFlag or 0 (and will use initialUsage to set) + int cpuAccessFlags = 0; ///< Combination of Resource::AccessFlag + }; + + /// Get the type + SLANG_FORCE_INLINE Type getType() const { return m_type; } + /// True if it's a texture derived type + SLANG_FORCE_INLINE bool isTexture() const { return int(m_type) >= int(Type::Texture1D); } + /// True if it's a buffer derived type + SLANG_FORCE_INLINE bool isBuffer() const { return m_type == Type::Buffer; } + + /// Get the descBase + const DescBase& getDescBase() const; + /// Returns true if can bind with flag + bool canBind(BindFlag::Enum bindFlag) const { return getDescBase().canBind(bindFlag); } + + /// For a usage gives the required binding flags + static const BindFlag::Enum s_requiredBinding[]; /// Maps Usage to bind flags required + + protected: + Resource(Type type): + m_type(type) + {} + + static void compileTimeAsserts(); + + Type m_type; +}; + +class BufferResource: public Resource +{ + public: + typedef Resource Parent; + + struct Desc: public DescBase + { + void init(size_t sizeInBytesIn) + { + sizeInBytes = sizeInBytesIn; + elementSize = 0; + format = Format::Unknown; + } + /// Set up default parameters based on usage + void setDefaults(Usage initialUsage); + + size_t sizeInBytes; ///< Total size in bytes + int elementSize; ///< Get the element stride. If > 0, this is a structured buffer + Format format; + }; + + /// Get the buffer description + SLANG_FORCE_INLINE const Desc& getDesc() const { return m_desc; } + + /// Ctor + BufferResource(const Desc& desc): + Parent(Type::Buffer), + m_desc(desc) + { + } + + protected: + Desc m_desc; +}; + +class TextureResource: public Resource +{ + public: + typedef Resource Parent; + + struct SampleDesc + { + void init() + { + numSamples = 1; + quality = 0; + } + int numSamples; ///< Number of samples per pixel + int quality; ///< The quality measure for the samples + }; + + struct Size + { + void init() + { + width = height = depth = 1; + } + void init(int widthIn, int heightIn = 1, int depthIn = 1) + { + width = widthIn; + height = heightIn; + depth = depthIn; + } + /// Given the type works out the maximum dimension size + int calcMaxDimension(Type type) const; + /// Given a size, calculates the size at a mip level + Size calcMipSize(int mipLevel) const; + + int width; ///< Width in pixels + int height; ///< Height in pixels (if 2d or 3d) + int depth; ///< Depth (if 3d) + }; + + struct Desc: public DescBase + { + /// Initialize with default values + void init(Type typeIn); + /// Initialize different dimensions. For cubemap, use init2D + void init1D(Format format, int width, int numMipMaps = 0); + void init2D(Type typeIn, Format format, int width, int height, int numMipMaps = 0); + void init3D(Format format, int width, int height, int depth, int numMipMaps = 0); + + /// Given the type, calculates the number of mip maps. 0 on error + int calcNumMipLevels() const; + /// Calculate the total number of sub resources. 0 on error. + int calcNumSubResources() const; + + /// Calculate the effective array size - in essence the amount if mip map sets needed. + /// In practice takes into account if the arraySize is 0 (it's not an array, but it will still have at least one mip set) + /// and if the type is a cubemap (multiplies the amount of mip sets by 6) + int calcEffectiveArraySize() const; + + /// Use type to fix the size values (and array size). + /// For example a 1d texture, should have height and depth set to 1. + void fixSize(); + + /// Set up default parameters based on type and usage + void setDefaults(Usage initialUsage); + + Size size; + + int arraySize; ///< Array size + + int numMipLevels; ///< Number of mip levels - if 0 will create all mip levels + Format format; ///< The resources format + SampleDesc sampleDesc; ///< How the resource is sampled + }; + + /// The ordering of the subResources is + /// forall (effectiveArraySize) + /// forall (mip levels) + /// forall (depth levels) + struct Data + { + ptrdiff_t* mipRowStrides; ///< The row stride for a mip map + int numMips; ///< The number of mip maps + const void*const* subResources; ///< Pointers to each full mip subResource + int numSubResources; ///< The total amount of subResources. Typically = numMips * depth * arraySize + }; + + /// Get the description of the texture + SLANG_FORCE_INLINE const Desc& getDesc() const { return m_desc; } + + /// Ctor + TextureResource(const Desc& desc): + Parent(desc.type), + m_desc(desc) + { + } + + SLANG_FORCE_INLINE static int calcMipSize(int width, int mipLevel) + { + width = width >> mipLevel; + return width > 0 ? width : 1; + } + + protected: + Desc m_desc; +}; + +enum class ComparisonFunc : uint8_t +{ + Never = 0, + Less = 0x01, + Equal = 0x02, + LessEqual = 0x03, + Greater = 0x04, + NotEqual = 0x05, + GreaterEqual = 0x06, + Always = 0x07, +}; + +enum class TextureFilteringMode +{ + Point, + Linear, +}; + +enum class TextureAddressingMode +{ + Wrap, + ClampToEdge, + ClampToBorder, + MirrorRepeat, + MirrorOnce, +}; + +enum class TextureReductionOp +{ + Average, + Comparison, + Minimum, + Maximum, +}; + +class SamplerState : public Slang::RefObject +{ +public: + struct Desc + { + TextureFilteringMode minFilter = TextureFilteringMode::Linear; + TextureFilteringMode magFilter = TextureFilteringMode::Linear; + TextureFilteringMode mipFilter = TextureFilteringMode::Linear; + TextureReductionOp reductionOp = TextureReductionOp::Average; + TextureAddressingMode addressU = TextureAddressingMode::Wrap; + TextureAddressingMode addressV = TextureAddressingMode::Wrap; + TextureAddressingMode addressW = TextureAddressingMode::Wrap; + float mipLODBias = 0.0f; + uint32_t maxAnisotropy = 1; + ComparisonFunc comparisonFunc = ComparisonFunc::Never; + float borderColor[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + float minLOD = -FLT_MAX; + float maxLOD = FLT_MAX; + }; +}; + +enum class DescriptorSlotType +{ + Unknown, + + Sampler, + CombinedImageSampler, + SampledImage, + StorageImage, + UniformTexelBuffer, + StorageTexelBuffer, + UniformBuffer, + StorageBuffer, + DynamicUniformBuffer, + DynamicStorageBuffer, + InputAttachment, +}; + +class DescriptorSetLayout : public Slang::RefObject +{ +public: + struct SlotRangeDesc + { + DescriptorSlotType type = DescriptorSlotType::Unknown; + UInt count = 1; + + SlotRangeDesc() + {} + + SlotRangeDesc( + DescriptorSlotType type, + UInt count = 1) + : type(type) + , count(count) + {} + }; + + struct Desc + { + UInt slotRangeCount = 0; + SlotRangeDesc const* slotRanges = nullptr; + }; +}; + +class PipelineLayout : public Slang::RefObject +{ +public: + struct DescriptorSetDesc + { + DescriptorSetLayout* layout = nullptr; + + DescriptorSetDesc() + {} + + DescriptorSetDesc( + DescriptorSetLayout* layout) + : layout(layout) + {} + }; + + struct Desc + { + UInt renderTargetCount = 0; + UInt descriptorSetCount = 0; + DescriptorSetDesc const* descriptorSets = nullptr; + }; +}; + +class ResourceView : public Slang::RefObject +{ +public: + enum class Type + { + Unknown, + + RenderTarget, + DepthStencil, + ShaderResource, + UnorderedAccess, + }; + + struct Desc + { + Type type; + Format format; + }; +}; + +class DescriptorSet : public Slang::RefObject +{ +public: + virtual void setConstantBuffer(UInt range, UInt index, BufferResource* buffer) = 0; + virtual void setResource(UInt range, UInt index, ResourceView* view) = 0; + virtual void setSampler(UInt range, UInt index, SamplerState* sampler) = 0; + virtual void setCombinedTextureSampler( + UInt range, + UInt index, + ResourceView* textureView, + SamplerState* sampler) = 0; +}; + +enum class StencilOp : uint8_t +{ + Keep, + Zero, + Replace, + IncrementSaturate, + DecrementSaturate, + Invert, + IncrementWrap, + DecrementWrap, +}; + +enum class FillMode : uint8_t +{ + Solid, + Wireframe, +}; + +enum class CullMode : uint8_t +{ + None, + Front, + Back, +}; + +enum class FrontFaceMode : uint8_t +{ + CounterClockwise, + Clockwise, +}; + +struct DepthStencilOpDesc +{ + StencilOp stencilFailOp = StencilOp::Keep; + StencilOp stencilDepthFailOp = StencilOp::Keep; + StencilOp stencilPassOp = StencilOp::Keep; + ComparisonFunc stencilFunc = ComparisonFunc::Always; +}; + +struct DepthStencilDesc +{ + bool depthTestEnable = true; + bool depthWriteEnable = true; + ComparisonFunc depthFunc = ComparisonFunc::Less; + + bool stencilEnable = false; + uint32_t stencilReadMask = 0xFFFFFFFF; + uint32_t stencilWriteMask = 0xFFFFFFFF; + DepthStencilOpDesc frontFace; + DepthStencilOpDesc backFace; + + uint32_t stencilRef = 0; +}; + +struct RasterizerDesc +{ + FillMode fillMode = FillMode::Solid; + CullMode cullMode = CullMode::Back; + FrontFaceMode frontFace = FrontFaceMode::CounterClockwise; + int32_t depthBias = 0; + float depthBiasClamp = 0.0f; + float slopeScaledDepthBias = 0.0f; + bool depthClipEnable = true; + bool scissorEnable = false; + bool multisampleEnable = false; + bool antialiasedLineEnable = false; +}; + +struct GraphicsPipelineStateDesc +{ + ShaderProgram* program; + PipelineLayout* pipelineLayout; + InputLayout* inputLayout; + UInt framebufferWidth; + UInt framebufferHeight; + UInt renderTargetCount; + DepthStencilDesc depthStencil; + RasterizerDesc rasterizer; +}; + +struct ComputePipelineStateDesc +{ + ShaderProgram* program; + PipelineLayout* pipelineLayout; +}; + +class PipelineState : public Slang::RefObject +{ +public: +}; + +class Renderer: public Slang::RefObject +{ +public: + + struct Desc + { + int width; ///< Width in pixels + int height; ///< height in pixels + }; + + virtual SlangResult initialize(const Desc& desc, void* inWindowHandle) = 0; + + virtual void setClearColor(const float color[4]) = 0; + virtual void clearFrame() = 0; + + virtual void presentFrame() = 0; + + virtual TextureResource::Desc getSwapChainTextureDesc() = 0; + + /// Create a texture resource. initData holds the initialize data to set the contents of the texture when constructed. + virtual Result createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& desc, const TextureResource::Data* initData, TextureResource** outResource) = 0; + + /// Create a texture resource. initData holds the initialize data to set the contents of the texture when constructed. + inline RefPtr<TextureResource> createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& desc, const TextureResource::Data* initData = nullptr) + { + RefPtr<TextureResource> resource; + SLANG_RETURN_NULL_ON_FAIL(createTextureResource(initialUsage, desc, initData, resource.writeRef())); + return resource; + } + + /// Create a buffer resource + virtual Result createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& desc, const void* initData, BufferResource** outResource) = 0; + + inline RefPtr<BufferResource> createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& desc, const void* initData = nullptr) + { + RefPtr<BufferResource> resource; + SLANG_RETURN_NULL_ON_FAIL(createBufferResource(initialUsage, desc, initData, resource.writeRef())); + return resource; + } + + virtual Result createSamplerState(SamplerState::Desc const& desc, SamplerState** outSampler) = 0; + + inline RefPtr<SamplerState> createSamplerState(SamplerState::Desc const& desc) + { + RefPtr<SamplerState> sampler; + SLANG_RETURN_NULL_ON_FAIL(createSamplerState(desc, sampler.writeRef())); + return sampler; + } + + virtual Result createTextureView(TextureResource* texture, ResourceView::Desc const& desc, ResourceView** outView) = 0; + + inline RefPtr<ResourceView> createTextureView(TextureResource* texture, ResourceView::Desc const& desc) + { + RefPtr<ResourceView> view; + SLANG_RETURN_NULL_ON_FAIL(createTextureView(texture, desc, view.writeRef())); + return view; + } + + virtual Result createBufferView(BufferResource* buffer, ResourceView::Desc const& desc, ResourceView** outView) = 0; + + inline RefPtr<ResourceView> createBufferView(BufferResource* buffer, ResourceView::Desc const& desc) + { + RefPtr<ResourceView> view; + SLANG_RETURN_NULL_ON_FAIL(createBufferView(buffer, desc, view.writeRef())); + return view; + } + + virtual Result createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount, InputLayout** outLayout) = 0; + + inline RefPtr<InputLayout> createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount) + { + RefPtr<InputLayout> layout; + SLANG_RETURN_NULL_ON_FAIL(createInputLayout(inputElements, inputElementCount, layout.writeRef())); + return layout; + } + + virtual Result createDescriptorSetLayout(const DescriptorSetLayout::Desc& desc, DescriptorSetLayout** outLayout) = 0; + + inline RefPtr<DescriptorSetLayout> createDescriptorSetLayout(const DescriptorSetLayout::Desc& desc) + { + RefPtr<DescriptorSetLayout> layout; + SLANG_RETURN_NULL_ON_FAIL(createDescriptorSetLayout(desc, layout.writeRef())); + return layout; + } + + virtual Result createPipelineLayout(const PipelineLayout::Desc& desc, PipelineLayout** outLayout) = 0; + + inline RefPtr<PipelineLayout> createPipelineLayout(const PipelineLayout::Desc& desc) + { + RefPtr<PipelineLayout> layout; + SLANG_RETURN_NULL_ON_FAIL(createPipelineLayout(desc, layout.writeRef())); + return layout; + } + + virtual Result createDescriptorSet(DescriptorSetLayout* layout, DescriptorSet** outDescriptorSet) = 0; + + inline RefPtr<DescriptorSet> createDescriptorSet(DescriptorSetLayout* layout) + { + RefPtr<DescriptorSet> descriptorSet; + SLANG_RETURN_NULL_ON_FAIL(createDescriptorSet(layout, descriptorSet.writeRef())); + return descriptorSet; + } + + virtual Result createProgram(const ShaderProgram::Desc& desc, ShaderProgram** outProgram) = 0; + + inline RefPtr<ShaderProgram> createProgram(const ShaderProgram::Desc& desc) + { + RefPtr<ShaderProgram> program; + SLANG_RETURN_NULL_ON_FAIL(createProgram(desc, program.writeRef())); + return program; + } + + virtual Result createGraphicsPipelineState( + const GraphicsPipelineStateDesc& desc, + PipelineState** outState) = 0; + + inline RefPtr<PipelineState> createGraphicsPipelineState( + const GraphicsPipelineStateDesc& desc) + { + RefPtr<PipelineState> state; + SLANG_RETURN_NULL_ON_FAIL(createGraphicsPipelineState(desc, state.writeRef())); + return state; + } + + virtual Result createComputePipelineState( + const ComputePipelineStateDesc& desc, + PipelineState** outState) = 0; + + inline RefPtr<PipelineState> createComputePipelineState( + const ComputePipelineStateDesc& desc) + { + RefPtr<PipelineState> state; + SLANG_RETURN_NULL_ON_FAIL(createComputePipelineState(desc, state.writeRef())); + return state; + } + + /// Captures the back buffer and stores the result in surfaceOut. If the surface contains data - it will either be overwritten (if same size and format), or freed and a re-allocated. + virtual SlangResult captureScreenSurface(Surface& surfaceOut) = 0; + + virtual void* map(BufferResource* buffer, MapFlavor flavor) = 0; + virtual void unmap(BufferResource* buffer) = 0; + + virtual void setPrimitiveTopology(PrimitiveTopology topology) = 0; + + virtual void setDescriptorSet(PipelineType pipelineType, PipelineLayout* layout, UInt index, DescriptorSet* descriptorSet) = 0; + + virtual void setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets) = 0; + inline void setVertexBuffer(UInt slot, BufferResource* buffer, UInt stride, UInt offset = 0); + + virtual void setIndexBuffer(BufferResource* buffer, Format indexFormat, UInt offset = 0) = 0; + + virtual void setDepthStencilTarget(ResourceView* depthStencilView) = 0; + + virtual void setPipelineState(PipelineType pipelineType, PipelineState* state) = 0; + + virtual void draw(UInt vertexCount, UInt startVertex = 0) = 0; + virtual void drawIndexed(UInt indexCount, UInt startIndex = 0, UInt baseVertex = 0) = 0; + + virtual void dispatchCompute(int x, int y, int z) = 0; + + /// Commit any buffered state changes or draw calls. + /// presentFrame will commitAll implicitly before doing a present + virtual void submitGpuWork() = 0; + /// Blocks until Gpu work is complete + virtual void waitForGpu() = 0; + + /// Get the type of this renderer + virtual RendererType getRendererType() const = 0; +}; + +// ---------------------------------------------------------------------------------------- +inline void Renderer::setVertexBuffer(UInt slot, BufferResource* buffer, UInt stride, UInt offset) +{ + setVertexBuffers(slot, 1, &buffer, &stride, &offset); +} + +/// Functions that are around Renderer and it's types +struct RendererUtil +{ + /// Gets the size in bytes of a Format type. Returns 0 if a size is not defined/invalid + SLANG_FORCE_INLINE static size_t getFormatSize(Format format) { return s_formatSize[int(format)]; } + /// Given a renderer type, gets a projection style + static ProjectionStyle getProjectionStyle(RendererType type); + + /// Given the projection style returns an 'identity' matrix, which ensures x,y mapping to pixels is the same on all targets + static void getIdentityProjection(ProjectionStyle style, float projMatrix[16]); + + /// Get the binding style from the type + static BindingStyle getBindingStyle(RendererType type) { return s_rendererTypeToBindingStyle[int(type)]; } + + private: + static void compileTimeAsserts(); + static const uint8_t s_formatSize[]; // Maps Format::XXX to a size in bytes; + static const BindingStyle s_rendererTypeToBindingStyle[]; ///< Maps a RendererType to a BindingStyle +}; + +} // renderer_test |
