summaryrefslogtreecommitdiffstats
path: root/tools/slang-graphics/render.cpp
diff options
context:
space:
mode:
authorTim Foley <tfoleyNV@users.noreply.github.com>2018-06-28 11:14:48 -0700
committerGitHub <noreply@github.com>2018-06-28 11:14:48 -0700
commitdfe13b54286b27dd15f591455bbb86b7798285c2 (patch)
tree4a11f01feaae059b6c11bdfbe12a614228af6dd5 /tools/slang-graphics/render.cpp
parent22033f06573f900dc030c487b2c30feddf3d8f16 (diff)
Share graphics API layer between tests/examples (#603)
The `render-test` project has an in-progress graphics API abstraction layer, and it makes sense to share this code with our examples rather than write a bunch of redundant code between examples and tests. Most of this change is just moving files from `tools/render-test/*` to a new library project at `tools/slang-graphics/`. The most complicated code change there is renaming from `render_test` to `slang_graphics`. The existing `hello` example was ported to use the graphics API layer instead of raw D3D11 API calls. It is still hard-coded to use the D3D11 back-end and the `SLANG_DXBC` target, so more work is needed if we want to actually support multiple APIs in the examples. I also went ahead and implemented an extremely rudimentary set of APIs to abstract over the Windows platform calls that were being made in the example, so that we could potentially run that same example on other platforms. I did *not* port `render-test` to use those APIs, and I also did not implement them for anything but Windows (my assumption is that for most other platforms we would just use SDL2, and require people to ensure it is installed to their machine before building Slang examples).
Diffstat (limited to 'tools/slang-graphics/render.cpp')
-rw-r--r--tools/slang-graphics/render.cpp390
1 files changed, 390 insertions, 0 deletions
diff --git a/tools/slang-graphics/render.cpp b/tools/slang-graphics/render.cpp
new file mode 100644
index 000000000..3595f73c1
--- /dev/null
+++ b/tools/slang-graphics/render.cpp
@@ -0,0 +1,390 @@
+// render.cpp
+#include "render.h"
+
+#include "../../source/core/slang-math.h"
+
+namespace slang_graphics {
+using namespace Slang;
+
+/* static */const Resource::BindFlag::Enum Resource::s_requiredBinding[] =
+{
+ BindFlag::VertexBuffer, // VertexBuffer
+ BindFlag::IndexBuffer, // IndexBuffer
+ BindFlag::ConstantBuffer, // ConstantBuffer
+ BindFlag::StreamOutput, // StreamOut
+ BindFlag::RenderTarget, // RenderTager
+ BindFlag::DepthStencil, // DepthRead
+ BindFlag::DepthStencil, // DepthWrite
+ BindFlag::UnorderedAccess, // UnorderedAccess
+ BindFlag::PixelShaderResource, // PixelShaderResource
+ BindFlag::NonPixelShaderResource, // NonPixelShaderResource
+ BindFlag::Enum(BindFlag::PixelShaderResource | BindFlag::NonPixelShaderResource), // GenericRead
+};
+
+
+/* static */void Resource::compileTimeAsserts()
+{
+ SLANG_COMPILE_TIME_ASSERT(SLANG_COUNT_OF(s_requiredBinding) == int(Usage::CountOf));
+}
+
+static const Resource::DescBase s_emptyDescBase = {};
+
+const Resource::DescBase& Resource::getDescBase() const
+{
+ if (isBuffer())
+ {
+ return static_cast<const BufferResource *>(this)->getDesc();
+ }
+ else if (isTexture())
+ {
+ return static_cast<const TextureResource *>(this)->getDesc();
+ }
+ return s_emptyDescBase;
+}
+
+/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! RendererUtil !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+
+/* static */const uint8_t RendererUtil::s_formatSize[] =
+{
+ 0, // Unknown,
+
+ uint8_t(sizeof(float) * 4), // RGBA_Float32,
+ uint8_t(sizeof(float) * 3), // RGB_Float32,
+ uint8_t(sizeof(float) * 2), // RG_Float32,
+ uint8_t(sizeof(float) * 1), // R_Float32,
+
+ uint8_t(sizeof(uint32_t)), // RGBA_Unorm_UInt8,
+
+ uint8_t(sizeof(uint32_t)), // R_UInt32,
+
+ uint8_t(sizeof(float)), // D_Float32,
+ uint8_t(sizeof(uint32_t)), // D_Unorm24_S8,
+};
+
+/* static */const BindingStyle RendererUtil::s_rendererTypeToBindingStyle[] =
+{
+ BindingStyle::Unknown, // Unknown,
+ BindingStyle::DirectX, // DirectX11,
+ BindingStyle::DirectX, // DirectX12,
+ BindingStyle::OpenGl, // OpenGl,
+ BindingStyle::Vulkan, // Vulkan
+};
+
+/* static */void RendererUtil::compileTimeAsserts()
+{
+ SLANG_COMPILE_TIME_ASSERT(SLANG_COUNT_OF(s_formatSize) == int(Format::CountOf));
+ SLANG_COMPILE_TIME_ASSERT(SLANG_COUNT_OF(s_rendererTypeToBindingStyle) == int(RendererType::CountOf));
+}
+
+/* !!!!!!!!!!!!!!!!!!!!!!!!!!! BindingState::Desc !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+
+void BindingState::Desc::addSampler(const SamplerDesc& desc, const RegisterRange& registerRange)
+{
+ int descIndex = int(m_samplerDescs.Count());
+ m_samplerDescs.Add(desc);
+
+ Binding binding;
+ binding.bindingType = BindingType::Sampler;
+ binding.resource = nullptr;
+ binding.registerRange = registerRange;
+ binding.descIndex = descIndex;
+
+ m_bindings.Add(binding);
+}
+
+void BindingState::Desc::addResource(BindingType bindingType, Resource* resource, const RegisterRange& registerRange)
+{
+ assert(resource);
+
+ Binding binding;
+ binding.bindingType = bindingType;
+ binding.resource = resource;
+ binding.descIndex = -1;
+ binding.registerRange = registerRange;
+ m_bindings.Add(binding);
+}
+
+void BindingState::Desc::addCombinedTextureSampler(TextureResource* resource, const SamplerDesc& samplerDesc, const RegisterRange& registerRange)
+{
+ assert(resource);
+
+ int samplerDescIndex = int(m_samplerDescs.Count());
+ m_samplerDescs.Add(samplerDesc);
+
+ Binding binding;
+ binding.bindingType = BindingType::CombinedTextureSampler;
+ binding.resource = resource;
+ binding.descIndex = samplerDescIndex;
+ binding.registerRange = registerRange;
+ m_bindings.Add(binding);
+}
+
+void BindingState::Desc::clear()
+{
+ m_bindings.Clear();
+ m_samplerDescs.Clear();
+ m_numRenderTargets = 1;
+}
+
+int BindingState::Desc::findBindingIndex(Resource::BindFlag::Enum bindFlag, int registerIndex) const
+{
+ const int numBindings = int(m_bindings.Count());
+ for (int i = 0; i < numBindings; ++i)
+ {
+ const Binding& binding = m_bindings[i];
+ if (binding.resource && (binding.resource->getDescBase().bindFlags & bindFlag) != 0)
+ {
+ if (binding.registerRange.hasRegister(registerIndex))
+ {
+ return i;
+ }
+ }
+ }
+
+ return -1;
+}
+
+/* !!!!!!!!!!!!!!!!!!!!!!!!!!! TextureResource::Size !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+
+int TextureResource::Size::calcMaxDimension(Type type) const
+{
+ switch (type)
+ {
+ case Resource::Type::Texture1D: return this->width;
+ case Resource::Type::Texture3D: return std::max(std::max(this->width, this->height), this->depth);
+ case Resource::Type::TextureCube: // fallthru
+ case Resource::Type::Texture2D:
+ {
+ return std::max(this->width, this->height);
+ }
+ default: return 0;
+ }
+}
+
+TextureResource::Size TextureResource::Size::calcMipSize(int mipLevel) const
+{
+ Size size;
+ size.width = TextureResource::calcMipSize(this->width, mipLevel);
+ size.height = TextureResource::calcMipSize(this->height, mipLevel);
+ size.depth = TextureResource::calcMipSize(this->depth, mipLevel);
+ return size;
+}
+
+/* !!!!!!!!!!!!!!!!!!!!!!!!! BufferResource::Desc !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+
+void BufferResource::Desc::setDefaults(Usage initialUsage)
+{
+ if (this->bindFlags == 0)
+ {
+ this->bindFlags = Resource::s_requiredBinding[int(initialUsage)];
+ }
+}
+
+/* !!!!!!!!!!!!!!!!!!!!!!!!! TextureResource::Desc !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+
+int TextureResource::Desc::calcNumMipLevels() const
+{
+ const int maxDimensionSize = this->size.calcMaxDimension(type);
+ return (maxDimensionSize > 0) ? (Math::Log2Floor(maxDimensionSize) + 1) : 0;
+}
+
+int TextureResource::Desc::calcNumSubResources() const
+{
+ const int numMipMaps = (this->numMipLevels > 0) ? this->numMipLevels : calcNumMipLevels();
+ const int arrSize = (this->arraySize > 0) ? this->arraySize : 1;
+
+ switch (type)
+ {
+ case Resource::Type::Texture1D:
+ case Resource::Type::Texture2D:
+ {
+ return numMipMaps * arrSize;
+ }
+ case Resource::Type::Texture3D:
+ {
+ // can't have arrays of 3d textures
+ assert(this->arraySize <= 1);
+ return numMipMaps * this->size.depth;
+ }
+ case Resource::Type::TextureCube:
+ {
+ // There are 6 faces to a cubemap
+ return numMipMaps * arrSize * 6;
+ }
+ default: return 0;
+ }
+}
+
+void TextureResource::Desc::fixSize()
+{
+ switch (type)
+ {
+ case Resource::Type::Texture1D:
+ {
+ this->size.height = 1;
+ this->size.depth = 1;
+ break;
+ }
+ case Resource::Type::TextureCube:
+ case Resource::Type::Texture2D:
+ {
+ this->size.depth = 1;
+ break;
+ }
+ case Resource::Type::Texture3D:
+ {
+ // Can't have an array
+ this->arraySize = 0;
+ break;
+ }
+ default: break;
+ }
+}
+
+void TextureResource::Desc::setDefaults(Usage initialUsage)
+{
+ fixSize();
+ if (this->bindFlags == 0)
+ {
+ this->bindFlags = Resource::s_requiredBinding[int(initialUsage)];
+ }
+ if (this->numMipLevels <= 0)
+ {
+ this->numMipLevels = calcNumMipLevels();
+ }
+}
+
+int TextureResource::Desc::calcEffectiveArraySize() const
+{
+ const int arrSize = (this->arraySize > 0) ? this->arraySize : 1;
+
+ switch (type)
+ {
+ case Resource::Type::Texture1D: // fallthru
+ case Resource::Type::Texture2D:
+ {
+ return arrSize;
+ }
+ case Resource::Type::TextureCube: return arrSize * 6;
+ case Resource::Type::Texture3D: return 1;
+ default: return 0;
+ }
+}
+
+void TextureResource::Desc::init(Type typeIn)
+{
+ this->type = typeIn;
+ this->size.init();
+
+ this->format = Format::Unknown;
+ this->arraySize = 0;
+ this->numMipLevels = 0;
+ this->sampleDesc.init();
+
+ this->bindFlags = 0;
+ this->cpuAccessFlags = 0;
+}
+
+void TextureResource::Desc::init1D(Format formatIn, int widthIn, int numMipMapsIn)
+{
+ this->type = Type::Texture1D;
+ this->size.init(widthIn);
+
+ this->format = format;
+ this->arraySize = 0;
+ this->numMipLevels = numMipMapsIn;
+ this->sampleDesc.init();
+
+ this->bindFlags = 0;
+ this->cpuAccessFlags = 0;
+}
+
+void TextureResource::Desc::init2D(Type typeIn, Format formatIn, int widthIn, int heightIn, int numMipMapsIn)
+{
+ assert(typeIn == Type::Texture2D || typeIn == Type::TextureCube);
+
+ this->type = type;
+ this->size.init(widthIn, heightIn);
+
+ this->format = format;
+ this->arraySize = 0;
+ this->numMipLevels = numMipMapsIn;
+ this->sampleDesc.init();
+
+ this->bindFlags = 0;
+ this->cpuAccessFlags = 0;
+}
+
+void TextureResource::Desc::init3D(Format formatIn, int widthIn, int heightIn, int depthIn, int numMipMapsIn)
+{
+ this->type = Type::Texture3D;
+ this->size.init(widthIn, heightIn, depthIn);
+
+ this->format = format;
+ this->arraySize = 0;
+ this->numMipLevels = numMipMapsIn;
+ this->sampleDesc.init();
+
+ this->bindFlags = 0;
+ this->cpuAccessFlags = 0;
+}
+
+/* !!!!!!!!!!!!!!!!!!!!!!!!! RennderUtil !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+
+ProjectionStyle RendererUtil::getProjectionStyle(RendererType type)
+{
+ switch (type)
+ {
+ case RendererType::DirectX11:
+ case RendererType::DirectX12:
+ {
+ return ProjectionStyle::DirectX;
+ }
+ case RendererType::OpenGl: return ProjectionStyle::OpenGl;
+ case RendererType::Vulkan: return ProjectionStyle::Vulkan;
+ case RendererType::Unknown: return ProjectionStyle::Unknown;
+ default:
+ {
+ assert(!"Unhandled type");
+ return ProjectionStyle::Unknown;
+ }
+ }
+}
+
+/* static */void RendererUtil::getIdentityProjection(ProjectionStyle style, float projMatrix[16])
+{
+ switch (style)
+ {
+ case ProjectionStyle::DirectX:
+ case ProjectionStyle::OpenGl:
+ {
+ static const float kIdentity[] =
+ {
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1
+ };
+ ::memcpy(projMatrix, kIdentity, sizeof(kIdentity));
+ break;
+ }
+ case ProjectionStyle::Vulkan:
+ {
+ static const float kIdentity[] =
+ {
+ 1, 0, 0, 0,
+ 0, -1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1
+ };
+ ::memcpy(projMatrix, kIdentity, sizeof(kIdentity));
+ break;
+ }
+ default:
+ {
+ assert(!"Not handled");
+ }
+ }
+}
+
+} // renderer_test