diff options
Diffstat (limited to 'tools/render-test/cpu-memory-binding.cpp')
| -rw-r--r-- | tools/render-test/cpu-memory-binding.cpp | 450 |
1 files changed, 450 insertions, 0 deletions
diff --git a/tools/render-test/cpu-memory-binding.cpp b/tools/render-test/cpu-memory-binding.cpp new file mode 100644 index 000000000..157716b60 --- /dev/null +++ b/tools/render-test/cpu-memory-binding.cpp @@ -0,0 +1,450 @@ + +#include "cpu-memory-binding.h" + +#include "../../slang-com-helper.h" + +#define SLANG_PRELUDE_NAMESPACE CPPPrelude +#include "../../prelude/slang-cpp-types.h" + +namespace renderer_test { +using namespace Slang; + +CPUMemoryBinding::CPUMemoryBinding() +{ + m_arena.init(1024, 16); +} + +CPUMemoryBinding::Buffer CPUMemoryBinding::_allocateBuffer(size_t size) +{ + Buffer buffer; + + // Use 16 byte alignment so works for all common types including typical simd + void* data = m_arena.allocateAligned(size, 16); + ::memset(data, 0, size); + + buffer.m_data = (uint8_t*)data; + buffer.m_sizeInBytes = size; + + m_allBuffers.add(buffer); + return buffer; +} + +CPUMemoryBinding::Buffer CPUMemoryBinding::_allocateBuffer(size_t size, const void* initialData, size_t initialSize) +{ + SLANG_ASSERT(initialSize <= size); + Buffer buffer = _allocateBuffer(size); + + if (initialData) + { + memcpy(buffer.m_data, initialData, initialSize); + } + + return buffer; +} + +SlangResult CPUMemoryBinding::init(slang::ShaderReflection* reflection) +{ + m_reflection = reflection; + m_rootBuffer = Buffer(); + + m_allBuffers.clear(); + m_arena.deallocateAll(); + + size_t globalConstantBuffer = reflection->getGlobalConstantBufferSize(); + + size_t rootSizeInBytes = 0; + const int parameterCount = reflection->getParameterCount(); + for (int i = 0; i < parameterCount; ++i) + { + auto parameter = reflection->getParameterByIndex(i); + + auto offset = parameter->getOffset(); + + auto typeLayout = parameter->getTypeLayout(); + auto sizeInBytes = typeLayout->getSize(); + + size_t endOffset = offset + sizeInBytes; + + rootSizeInBytes = (endOffset > rootSizeInBytes) ? endOffset : rootSizeInBytes; + } + SLANG_ASSERT(rootSizeInBytes == globalConstantBuffer); + + // Allocate the root (0 is the root) + m_rootBuffer = _allocateBuffer(rootSizeInBytes); + + { + uint8_t*const buffer = m_rootBuffer.m_data; + for (int i = 0; i < parameterCount; ++i) + { + auto parameter = reflection->getParameterByIndex(i); + auto offset = parameter->getOffset(); + + auto typeLayout = parameter->getTypeLayout(); + Buffer paramBuffer; + SLANG_RETURN_ON_FAIL(_add(parameter, typeLayout, buffer + offset, paramBuffer)); + } + } + + return SLANG_OK; +} + +SlangResult CPUMemoryBinding::_add(slang::VariableLayoutReflection* varLayout, slang::TypeLayoutReflection* typeLayout, void* dst, Buffer& outBuffer) +{ + const auto kind = typeLayout->getKind(); + switch (kind) + { + case slang::TypeReflection::Kind::Array: + { + auto elementTypeLayout = typeLayout->getElementTypeLayout(); + auto elementCount = int(typeLayout->getElementCount()); + const size_t stride = elementTypeLayout->getSize(); + uint8_t* cur = (uint8_t*)dst; + for (int i = 0; i < elementCount; ++i) + { + Buffer elementBuffer; + _add(nullptr, elementTypeLayout, cur, elementBuffer); + cur += stride; + } + break; + } + case slang::TypeReflection::Kind::Struct: + { + auto structTypeLayout = typeLayout; + //auto name = structTypeLayout->getName(); + //SLANG_UNUSED(name); + + auto fieldCount = structTypeLayout->getFieldCount(); + for (uint32_t ff = 0; ff < fieldCount; ++ff) + { + auto field = structTypeLayout->getFieldByIndex(ff); + auto offset = field->getOffset(); + + Buffer fieldBuffer; + SLANG_RETURN_ON_FAIL(_add(nullptr, field->getTypeLayout(), ((uint8_t*)dst) + offset, fieldBuffer)); + } + break; + } + case slang::TypeReflection::Kind::ConstantBuffer: + { + SLANG_ASSERT(typeLayout->getSize() == sizeof(void*)); + + auto elementTypeLayout = typeLayout->getElementTypeLayout(); + const size_t elementSize = elementTypeLayout->getSize(); + + outBuffer = _allocateBuffer(elementSize); + + // Constant buffers map to a pointer + *(void**)dst = outBuffer.m_data; + + // On CPU constant buffers can contain pointers to other resources (including constant buffers) + Buffer innerBuffer; + SLANG_RETURN_ON_FAIL(_add(nullptr, elementTypeLayout, outBuffer.m_data, innerBuffer)); + break; + } + default: break; + } + return SLANG_OK; +} + +slang::VariableLayoutReflection* CPUMemoryBinding::getParameterByName(const char* name) +{ + const int parameterCount = m_reflection->getParameterCount(); + for (int i = 0; i < parameterCount; ++i) + { + auto parameter = m_reflection->getParameterByIndex(i); + const char* paramName = parameter->getName(); + if (strcmp(name, paramName) == 0) + { + return parameter; + } + } + return nullptr; +} + +CPUMemoryBinding::Location CPUMemoryBinding::find(const char* name) +{ + auto varLayout = getParameterByName(name); + if (varLayout == nullptr) + { + return Location(); + } + + Location location; + location.m_cur = m_rootBuffer.m_data + varLayout->getOffset(); + location.m_typeLayout = varLayout->getTypeLayout(); + + return location; +} + +CPUMemoryBinding::Location CPUMemoryBinding::toField(const Location& location, const char* name) +{ + if (!location.isValid()) + { + return location; + } + + auto typeLayout = location.m_typeLayout; + uint8_t* cur = location.m_cur; + + // Strip constantBuffer wrapping + { + const auto kind = typeLayout->getKind(); + if (kind == slang::TypeReflection::Kind::ConstantBuffer) + { + // Follow the pointer + cur = *(uint8_t**)cur; + typeLayout = typeLayout->getElementTypeLayout(); + } + } + + { + const auto kind = typeLayout->getKind(); + if (kind == slang::TypeReflection::Kind::Struct) + { + slang::VariableLayoutReflection* varLayout = nullptr; + auto fieldCount = typeLayout->getFieldCount(); + for (uint32_t ff = 0; ff < fieldCount; ++ff) + { + auto field = typeLayout->getFieldByIndex(ff); + if (strcmp(field->getName(), name) == 0) + { + Location newLocation; + newLocation.m_cur = cur + field->getOffset(); + newLocation.m_typeLayout = field->getTypeLayout(); + return newLocation; + } + } + } + } + + return Location(); +} + +CPUMemoryBinding::Location CPUMemoryBinding::toIndex(const Location& location, int index) +{ + if (!location.isValid()) + { + return location; + } + + auto typeLayout = location.m_typeLayout; + uint8_t* cur = location.m_cur; + + const auto kind = typeLayout->getKind(); + switch (kind) + { + case slang::TypeReflection::Kind::Array: + { + auto elementTypeLayout = typeLayout->getElementTypeLayout(); + auto elementCount = int(typeLayout->getElementCount()); + + if (index < 0 || index >= elementCount) + { + SLANG_ASSERT(index < elementCount); + return Location(); + } + + Location newLocation; + newLocation.m_typeLayout = elementTypeLayout; + newLocation.m_cur = cur + elementTypeLayout->getSize() * index; + return newLocation; + } + default: break; + } + + return Location(); +} + + +SlangResult CPUMemoryBinding::setBufferContents(const Location& location, const void* initialData, size_t sizeInBytes) +{ + if (!location.isValid()) + { + return SLANG_FAIL; + } + + auto typeLayout = location.m_typeLayout; + uint8_t* cur = location.m_cur; + + const auto kind = typeLayout->getKind(); + switch (kind) + { + case slang::TypeReflection::Kind::ConstantBuffer: + { + typeLayout = typeLayout->getElementTypeLayout(); + + size_t bufferSize = typeLayout->getSize(); + sizeInBytes = (sizeInBytes > bufferSize) ? bufferSize : sizeInBytes; + + void* buffer = *(void**)cur; + memcpy(buffer, initialData, sizeInBytes); + return SLANG_OK; + } + default: break; + } + return SLANG_FAIL; +} + +SlangResult CPUMemoryBinding::setNewBuffer(const Location& location, const void* initialData, size_t sizeInBytes, Buffer& outBuffer) +{ + if (!location.isValid()) + { + return SLANG_FAIL; + } + + auto typeLayout = location.m_typeLayout; + uint8_t* cur = location.m_cur; + + const auto kind = typeLayout->getKind(); + switch (kind) + { + case slang::TypeReflection::Kind::ConstantBuffer: + { + // All should be allocated (!) + SLANG_ASSERT(typeLayout->getSize() == sizeof(void*)); + SLANG_ASSERT(*(void**)cur); + return SLANG_FAIL; + } + case slang::TypeReflection::Kind::Resource: + { + auto type = typeLayout->getType(); + auto shape = type->getResourceShape(); + + switch (shape & SLANG_RESOURCE_BASE_SHAPE_MASK) + { + case SLANG_STRUCTURED_BUFFER: + { + auto elementTypeLayout = typeLayout->getElementTypeLayout(); + size_t elementSize = elementTypeLayout->getSize(SLANG_PARAMETER_CATEGORY_UNIFORM); + + // We don't know the size of the buffer, but we can work it out, based on what is initialized + const int numElements = int((sizeInBytes + elementSize - 1) / elementSize); + + const size_t bufferSize = numElements * elementSize; + SLANG_ASSERT(bufferSize >= sizeInBytes); + + outBuffer = _allocateBuffer(bufferSize, initialData, sizeInBytes); + + CPPPrelude::StructuredBuffer<uint8_t>& dstBuf = *(CPPPrelude::StructuredBuffer<uint8_t>*)cur; + dstBuf.data = (uint8_t*)outBuffer.m_data; + dstBuf.count = numElements; + return SLANG_OK; + } + case SLANG_BYTE_ADDRESS_BUFFER: + { + const size_t bufferSize = (sizeInBytes + 3) & ~size_t(3); + + outBuffer = _allocateBuffer(bufferSize, initialData, sizeInBytes); + + CPPPrelude::ByteAddressBuffer& dstBuf = *(CPPPrelude::ByteAddressBuffer*)cur; + dstBuf.data = (uint32_t*)outBuffer.m_data; + dstBuf.sizeInBytes = bufferSize; + return SLANG_OK; + } + } + break; + } + default: break; + } + + return SLANG_FAIL; +} + +SlangResult CPUMemoryBinding::setObject(const Location& location, void* object) +{ + if (!location.isValid()) + { + return SLANG_FAIL; + } + + auto typeLayout = location.m_typeLayout; + uint8_t* cur = location.m_cur; + + const auto kind = typeLayout->getKind(); + switch (kind) + { + default: + break; + + case slang::TypeReflection::Kind::ParameterBlock: + { + auto elementTypeLayout = typeLayout->getElementTypeLayout(); + SLANG_UNUSED(elementTypeLayout); + break; + } + case slang::TypeReflection::Kind::TextureBuffer: + { + auto elementTypeLayout = typeLayout->getElementTypeLayout(); + SLANG_UNUSED(elementTypeLayout); + break; + } + case slang::TypeReflection::Kind::ShaderStorageBuffer: + { + auto elementTypeLayout = typeLayout->getElementTypeLayout(); + SLANG_UNUSED(elementTypeLayout); + break; + } + case slang::TypeReflection::Kind::GenericTypeParameter: + { + const char* name = typeLayout->getName(); + SLANG_UNUSED(name); + break; + } + case slang::TypeReflection::Kind::Interface: + { + const char* name = typeLayout->getName(); + SLANG_UNUSED(name); + break; + } + case slang::TypeReflection::Kind::Resource: + { + auto type = typeLayout->getType(); + auto shape = type->getResourceShape(); + + //auto access = type->getResourceAccess(); + + switch (shape & SLANG_RESOURCE_BASE_SHAPE_MASK) + { + default: + assert(!"unhandled case"); + break; + case SLANG_TEXTURE_1D: + case SLANG_TEXTURE_2D: + case SLANG_TEXTURE_3D: + case SLANG_TEXTURE_CUBE: + case SLANG_TEXTURE_BUFFER: + { + *(void**)cur = object; + return SLANG_OK; + } + } + if (shape & SLANG_TEXTURE_ARRAY_FLAG) + { + + } + if (shape & SLANG_TEXTURE_MULTISAMPLE_FLAG) + { + + } + + break; + } + } + + return SLANG_FAIL; +} + +SlangResult CPUMemoryBinding::setInplace(const Location& location, const void* data, size_t sizeInBytes) +{ + if (!location.isValid()) + { + return SLANG_FAIL; + } + + size_t dstSize = location.m_typeLayout->getSize(); + sizeInBytes = (sizeInBytes > dstSize) ? dstSize : sizeInBytes; + memcpy(location.m_cur, data, sizeInBytes); + return SLANG_OK; +} + +} // renderer_test |
