diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2019-09-13 15:59:15 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-09-13 15:59:15 -0400 |
| commit | c2e5d2468ad6a38cdb8a067da0678302f6cc6066 (patch) | |
| tree | 97c448d28e54068d84c422e9f172996b7a95f1ed /tools/gfx/open-gl/render-gl.cpp | |
| parent | 0b6321b3f08c48e37e6b8256d420f05d9727fb5a (diff) | |
Refactor render-test to make cross platform (#1053)
* First pass of render-test refactor.
* Make window construction a function that can choose an implementation.
* Remove OpenGL as currently has windows dependency.
* Disable Vulkan as Renderer impl has dependency on windows.
* Pass Window in as parameter of 'update'.
* Add win-window.cpp as was missing.
* Fix warning on windows about signs during comparison.
Diffstat (limited to 'tools/gfx/open-gl/render-gl.cpp')
| -rw-r--r-- | tools/gfx/open-gl/render-gl.cpp | 1504 |
1 files changed, 1504 insertions, 0 deletions
diff --git a/tools/gfx/open-gl/render-gl.cpp b/tools/gfx/open-gl/render-gl.cpp new file mode 100644 index 000000000..91c31b71d --- /dev/null +++ b/tools/gfx/open-gl/render-gl.cpp @@ -0,0 +1,1504 @@ +// render-gl.cpp +#include "render-gl.h" + +//WORKING:#include "options.h" +#include "../render.h" + +#include <stdio.h> +#include <stdlib.h> +#include "core/slang-basic.h" +#include "core/slang-secure-crt.h" +#include "external/stb/stb_image_write.h" + +#include "../surface.h" + +// TODO(tfoley): eventually we should be able to run these +// tests on non-Windows targets to confirm that cross-compilation +// at least *works* on those platforms... +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX +#include <Windows.h> +#undef WIN32_LEAN_AND_MEAN +#undef NOMINMAX + +#ifdef _MSC_VER +#include <stddef.h> +#if (_MSC_VER < 1900) +#define snprintf sprintf_s +#endif +#endif + +#pragma comment(lib, "opengl32") + +#include <GL/GL.h> +#include "external/glext.h" + +// We define an "X-macro" for mapping over loadable OpenGL +// extension entry point that we will use, so that we can +// easily write generic code to iterate over them. +#define MAP_GL_EXTENSION_FUNCS(F) \ + F(glCreateProgram, PFNGLCREATEPROGRAMPROC) \ + F(glCreateShader, PFNGLCREATESHADERPROC) \ + F(glShaderSource, PFNGLSHADERSOURCEPROC) \ + F(glCompileShader, PFNGLCOMPILESHADERPROC) \ + F(glGetShaderiv, PFNGLGETSHADERIVPROC) \ + F(glDeleteShader, PFNGLDELETESHADERPROC) \ + F(glAttachShader, PFNGLATTACHSHADERPROC) \ + F(glLinkProgram, PFNGLLINKPROGRAMPROC) \ + F(glGetProgramiv, PFNGLGETPROGRAMIVPROC) \ + F(glGetProgramInfoLog, PFNGLGETPROGRAMINFOLOGPROC) \ + F(glDeleteProgram, PFNGLDELETEPROGRAMPROC) \ + F(glGetShaderInfoLog, PFNGLGETSHADERINFOLOGPROC) \ + F(glGenBuffers, PFNGLGENBUFFERSPROC) \ + F(glBindBuffer, PFNGLBINDBUFFERPROC) \ + F(glBufferData, PFNGLBUFFERDATAPROC) \ + F(glDeleteBuffers, PFNGLDELETEBUFFERSPROC) \ + F(glMapBuffer, PFNGLMAPBUFFERPROC) \ + F(glUnmapBuffer, PFNGLUNMAPBUFFERPROC) \ + F(glUseProgram, PFNGLUSEPROGRAMPROC) \ + F(glBindBufferBase, PFNGLBINDBUFFERBASEPROC) \ + F(glVertexAttribPointer, PFNGLVERTEXATTRIBPOINTERPROC) \ + F(glEnableVertexAttribArray, PFNGLENABLEVERTEXATTRIBARRAYPROC) \ + F(glDisableVertexAttribArray, PFNGLDISABLEVERTEXATTRIBARRAYPROC) \ + F(glDebugMessageCallback, PFNGLDEBUGMESSAGECALLBACKPROC) \ + F(glDispatchCompute, PFNGLDISPATCHCOMPUTEPROC) \ + F(glActiveTexture, PFNGLACTIVETEXTUREPROC) \ + F(glCreateSamplers, PFNGLCREATESAMPLERSPROC) \ + F(glDeleteSamplers, PFNGLDELETESAMPLERSPROC) \ + F(glBindSampler, PFNGLBINDSAMPLERPROC) \ + F(glTexImage3D, PFNGLTEXIMAGE3DPROC) \ + F(glSamplerParameteri, PFNGLSAMPLERPARAMETERIPROC) \ + /* end */ + +using namespace Slang; + +namespace gfx { + +class GLRenderer : public Renderer +{ +public: + + // Renderer implementation + virtual SlangResult initialize(const Desc& desc, void* inWindowHandle) override; + virtual const List<String>& getFeatures() override { return m_features; } + virtual void setClearColor(const float color[4]) override; + virtual void clearFrame() override; + virtual void presentFrame() override; + TextureResource::Desc getSwapChainTextureDesc() override; + + Result createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& desc, const TextureResource::Data* initData, TextureResource** outResource) override; + Result createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& desc, const void* initData, BufferResource** outResource) override; + Result createSamplerState(SamplerState::Desc const& desc, SamplerState** outSampler) override; + + Result createTextureView(TextureResource* texture, ResourceView::Desc const& desc, ResourceView** outView) override; + Result createBufferView(BufferResource* buffer, ResourceView::Desc const& desc, ResourceView** outView) override; + + Result createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount, InputLayout** outLayout) override; + + Result createDescriptorSetLayout(const DescriptorSetLayout::Desc& desc, DescriptorSetLayout** outLayout) override; + Result createPipelineLayout(const PipelineLayout::Desc& desc, PipelineLayout** outLayout) override; + Result createDescriptorSet(DescriptorSetLayout* layout, DescriptorSet** outDescriptorSet) override; + + Result createProgram(const ShaderProgram::Desc& desc, ShaderProgram** outProgram) override; + Result createGraphicsPipelineState(const GraphicsPipelineStateDesc& desc, PipelineState** outState) override; + Result createComputePipelineState(const ComputePipelineStateDesc& desc, PipelineState** outState) override; + + virtual SlangResult captureScreenSurface(Surface& surfaceOut) override; + + virtual void* map(BufferResource* buffer, MapFlavor flavor) override; + virtual void unmap(BufferResource* buffer) override; + virtual void setPrimitiveTopology(PrimitiveTopology topology) override; + + virtual void setDescriptorSet(PipelineType pipelineType, PipelineLayout* layout, UInt index, DescriptorSet* descriptorSet) override; + + virtual void setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets) override; + virtual void setIndexBuffer(BufferResource* buffer, Format indexFormat, UInt offset) override; + virtual void setDepthStencilTarget(ResourceView* depthStencilView) override; + void setViewports(UInt count, Viewport const* viewports) override; + void setScissorRects(UInt count, ScissorRect const* rects) override; + virtual void setPipelineState(PipelineType pipelineType, PipelineState* state) override; + virtual void draw(UInt vertexCount, UInt startVertex) override; + virtual void drawIndexed(UInt indexCount, UInt startIndex, UInt baseVertex) override; + virtual void dispatchCompute(int x, int y, int z) override; + virtual void submitGpuWork() override {} + virtual void waitForGpu() override {} + virtual RendererType getRendererType() const override { return RendererType::OpenGl; } + + GLRenderer(); + ~GLRenderer(); + + protected: + enum + { + kMaxVertexStreams = 16, + kMaxDescriptorSetCount = 8, + }; + struct VertexAttributeFormat + { + GLint componentCount; + GLenum componentType; + GLboolean normalized; + }; + + struct VertexAttributeDesc + { + VertexAttributeFormat format; + GLuint streamIndex; + GLsizei offset; + }; + + class InputLayoutImpl: public InputLayout + { + public: + VertexAttributeDesc m_attributes[kMaxVertexStreams]; + UInt m_attributeCount = 0; + }; + + class BufferResourceImpl: public BufferResource + { + public: + typedef BufferResource Parent; + + BufferResourceImpl(Usage initialUsage, const Desc& desc, WeakSink<GLRenderer>* renderer, GLuint id, GLenum target): + Parent(desc), + m_renderer(renderer), + m_handle(id), + m_initialUsage(initialUsage), + m_target(target) + {} + ~BufferResourceImpl() + { + if (auto renderer = m_renderer->get()) + { + renderer->glDeleteBuffers(1, &m_handle); + } + } + + Usage m_initialUsage; + RefPtr<WeakSink<GLRenderer> > m_renderer; + GLuint m_handle; + GLenum m_target; + }; + + class TextureResourceImpl: public TextureResource + { + public: + typedef TextureResource Parent; + + TextureResourceImpl(Usage initialUsage, const Desc& desc, WeakSink<GLRenderer>* renderer): + Parent(desc), + m_initialUsage(initialUsage), + m_renderer(renderer) + { + m_target = 0; + m_handle = 0; + } + + ~TextureResourceImpl() + { + if (m_handle) + { + glDeleteTextures(1, &m_handle); + } + } + + Usage m_initialUsage; + RefPtr<WeakSink<GLRenderer> > m_renderer; + GLenum m_target; + GLuint m_handle; + }; + + class SamplerStateImpl : public SamplerState + { + public: + GLuint m_samplerID; + }; + + class ResourceViewImpl : public ResourceView + { + }; + + class TextureViewImpl : public ResourceViewImpl + { + public: + RefPtr<TextureResourceImpl> m_resource; + GLuint m_textureID; + }; + + class BufferViewImpl : public ResourceViewImpl + { + public: + RefPtr<BufferResourceImpl> m_resource; + GLuint m_bufferID; + }; + + enum class GLDescriptorSlotType + { + ConstantBuffer, + CombinedTextureSampler, + + CountOf, + }; + + class DescriptorSetLayoutImpl : public DescriptorSetLayout + { + public: + struct RangeInfo + { + GLDescriptorSlotType type; + UInt arrayIndex; + }; + List<RangeInfo> m_ranges; + Int m_counts[int(GLDescriptorSlotType::CountOf)]; + }; + + class PipelineLayoutImpl : public PipelineLayout + { + public: + struct DescriptorSetInfo + { + RefPtr<DescriptorSetLayoutImpl> layout; + UInt baseArrayIndex[int(GLDescriptorSlotType::CountOf)]; + }; + + List<DescriptorSetInfo> m_sets; + }; + + class DescriptorSetImpl : public DescriptorSet + { + public: + virtual void setConstantBuffer(UInt range, UInt index, BufferResource* buffer) override; + virtual void setResource(UInt range, UInt index, ResourceView* view) override; + virtual void setSampler(UInt range, UInt index, SamplerState* sampler) override; + virtual void setCombinedTextureSampler( + UInt range, + UInt index, + ResourceView* textureView, + SamplerState* sampler) override; + + RefPtr<DescriptorSetLayoutImpl> m_layout; + List<RefPtr<BufferResourceImpl>> m_constantBuffers; + List<RefPtr<TextureViewImpl>> m_textures; + List<RefPtr<SamplerStateImpl>> m_samplers; + }; + + class ShaderProgramImpl : public ShaderProgram + { + public: + ShaderProgramImpl(WeakSink<GLRenderer>* renderer, GLuint id): + m_renderer(renderer), + m_id(id) + { + } + ~ShaderProgramImpl() + { + if (auto renderer = m_renderer->get()) + { + renderer->glDeleteProgram(m_id); + } + } + + GLuint m_id; + RefPtr<WeakSink<GLRenderer> > m_renderer; + }; + + class PipelineStateImpl : public PipelineState + { + public: + RefPtr<ShaderProgramImpl> m_program; + RefPtr<PipelineLayoutImpl> m_pipelineLayout; + RefPtr<InputLayoutImpl> m_inputLayout; + }; + + enum class GlPixelFormat + { + Unknown, + RGBA_Unorm_UInt8, + CountOf, + }; + + struct GlPixelFormatInfo + { + GLint internalFormat; // such as GL_RGBA8 + GLenum format; // such as GL_RGBA + GLenum formatType; // such as GL_UNSIGNED_BYTE + }; + +// void destroyBindingEntries(const BindingState::Desc& desc, const BindingDetail* details); + + void bindBufferImpl(int target, UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* offsets); + void flushStateForDraw(); + GLuint loadShader(GLenum stage, char const* source); + void debugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message); + + /// Returns GlPixelFormat::Unknown if not an equivalent + static GlPixelFormat _getGlPixelFormat(Format format); + + static void APIENTRY staticDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam); + static VertexAttributeFormat getVertexAttributeFormat(Format format); + + static void compileTimeAsserts(); + + HDC m_hdc; + HGLRC m_glContext; + float m_clearColor[4] = { 0, 0, 0, 0 }; + + RefPtr<PipelineStateImpl> m_currentPipelineState; + RefPtr<WeakSink<GLRenderer> > m_weakRenderer; + + RefPtr<DescriptorSetImpl> m_boundDescriptorSets[kMaxDescriptorSetCount]; + + GLenum m_boundPrimitiveTopology = GL_TRIANGLES; + GLuint m_boundVertexStreamBuffers[kMaxVertexStreams]; + UInt m_boundVertexStreamStrides[kMaxVertexStreams]; + UInt m_boundVertexStreamOffsets[kMaxVertexStreams]; + + Desc m_desc; + + List<String> m_features; + + // Declare a function pointer for each OpenGL + // extension function we need to load +#define DECLARE_GL_EXTENSION_FUNC(NAME, TYPE) TYPE NAME; + MAP_GL_EXTENSION_FUNCS(DECLARE_GL_EXTENSION_FUNC) +#undef DECLARE_GL_EXTENSION_FUNC + + static const GlPixelFormatInfo s_pixelFormatInfos[]; /// Maps GlPixelFormat to a format info +}; + +/* static */GLRenderer::GlPixelFormat GLRenderer::_getGlPixelFormat(Format format) +{ + switch (format) + { + case Format::RGBA_Unorm_UInt8: return GlPixelFormat::RGBA_Unorm_UInt8; + default: return GlPixelFormat::Unknown; + } +} + +/* static */ const GLRenderer::GlPixelFormatInfo GLRenderer::s_pixelFormatInfos[] = +{ + // internalType, format, formatType + { 0, 0, 0}, // GlPixelFormat::Unknown + { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE }, // GlPixelFormat::RGBA_Unorm_UInt8 +}; + +/* static */void GLRenderer::compileTimeAsserts() +{ + SLANG_COMPILE_TIME_ASSERT(SLANG_COUNT_OF(s_pixelFormatInfos) == int(GlPixelFormat::CountOf)); +} + +Renderer* createGLRenderer() +{ + return new GLRenderer(); +} + +void GLRenderer::debugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message) +{ + ::OutputDebugStringA("GL: "); + ::OutputDebugStringA(message); + ::OutputDebugStringA("\n"); + + switch (type) + { + case GL_DEBUG_TYPE_ERROR: + break; + default: + break; + } +} + + +GLRenderer::GLRenderer() +{ + m_weakRenderer = new WeakSink<GLRenderer>(this); +} + +GLRenderer::~GLRenderer() +{ + // We can destroy things whilst in this state + m_currentPipelineState.setNull(); + + // By resetting the weak pointer, other objects accessing through WeakSink<GLRenderer> will no longer + // be able to access this object which is entering a 'being destroyed' to 'destroyed' state + if (m_weakRenderer) + { + SLANG_ASSERT(m_weakRenderer->get() == this); + m_weakRenderer->detach(); + } +} + +/* static */void APIENTRY GLRenderer::staticDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) +{ + ((GLRenderer*)userParam)->debugCallback(source, type, id, severity, length, message); +} + +/* static */GLRenderer::VertexAttributeFormat GLRenderer::getVertexAttributeFormat(Format format) +{ + switch (format) + { + default: assert(!"unexpected"); return VertexAttributeFormat(); + +#define CASE(NAME, COUNT, TYPE, NORMALIZED) \ + case Format::NAME: do { VertexAttributeFormat result = {COUNT, TYPE, NORMALIZED}; return result; } while (0) + + CASE(RGBA_Float32, 4, GL_FLOAT, GL_FALSE); + CASE(RGB_Float32, 3, GL_FLOAT, GL_FALSE); + CASE(RG_Float32, 2, GL_FLOAT, GL_FALSE); + CASE(R_Float32, 1, GL_FLOAT, GL_FALSE); +#undef CASE + } +} + +void GLRenderer::bindBufferImpl(int target, UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* offsets) +{ + for (UInt ii = 0; ii < slotCount; ++ii) + { + UInt slot = startSlot + ii; + + BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(buffers[ii]); + GLuint bufferID = buffer ? buffer->m_handle : 0; + + assert(!offsets || !offsets[ii]); + + glBindBufferBase(target, (GLuint)slot, bufferID); + } +} + +void GLRenderer::flushStateForDraw() +{ + auto inputLayout = m_currentPipelineState->m_inputLayout.Ptr(); + auto attrCount = Index(inputLayout->m_attributeCount); + for (Index ii = 0; ii < attrCount; ++ii) + { + auto& attr = inputLayout->m_attributes[ii]; + + auto streamIndex = attr.streamIndex; + + glBindBuffer(GL_ARRAY_BUFFER, m_boundVertexStreamBuffers[streamIndex]); + + glVertexAttribPointer( + (GLuint)ii, + attr.format.componentCount, + attr.format.componentType, + attr.format.normalized, + (GLsizei)m_boundVertexStreamStrides[streamIndex], + (GLvoid*)(attr.offset + m_boundVertexStreamOffsets[streamIndex])); + + glEnableVertexAttribArray((GLuint)ii); + } + for (Index ii = attrCount; ii < kMaxVertexStreams; ++ii) + { + glDisableVertexAttribArray((GLuint)ii); + } + + // Next bind the descriptor sets as required by the layout + auto pipelineLayout = m_currentPipelineState->m_pipelineLayout; + auto descriptorSetCount = pipelineLayout->m_sets.getCount(); + for(Index ii = 0; ii < descriptorSetCount; ++ii) + { + auto descriptorSet = m_boundDescriptorSets[ii]; + auto descriptorSetInfo = pipelineLayout->m_sets[ii]; + auto descriptorSetLayout = descriptorSetInfo.layout; + + // TODO: need to validate that `descriptorSet->m_layout` matches + // `descriptorSetLayout`. + + { + // First we will bind any uniform buffers that were specified. + + auto slotTypeIndex = int(GLDescriptorSlotType::ConstantBuffer); + auto count = descriptorSetLayout->m_counts[slotTypeIndex]; + auto baseIndex = descriptorSetInfo.baseArrayIndex[slotTypeIndex]; + + for(Int ii = 0; ii < count; ++ii) + { + auto bufferImpl = descriptorSet->m_constantBuffers[ii]; + glBindBufferBase(GL_UNIFORM_BUFFER, GLuint(ii), bufferImpl->m_handle); + } + } + + + { + // Next we will bind any combined texture/sampler slots. + + auto slotTypeIndex = int(GLDescriptorSlotType::CombinedTextureSampler); + auto count = descriptorSetLayout->m_counts[slotTypeIndex]; + auto baseIndex = descriptorSetInfo.baseArrayIndex[slotTypeIndex]; + + // TODO: We should be able to use a single call to glBindTextures here, + // rather than a loop. This would also eliminate the need to retain + // the appropriate target (e.g., `GL_TEXTURE_2D` for binding). + + for(Int ii = 0; ii < count; ++ii) + { + auto textureViewImpl = descriptorSet->m_textures[ii]; + auto samplerImpl = descriptorSet->m_samplers[ii]; + + glActiveTexture(GLuint(GL_TEXTURE0 + ii)); + glBindTexture(GL_TEXTURE_2D, textureViewImpl->m_textureID); + + glBindSampler(GLuint(baseIndex + ii), samplerImpl->m_samplerID); + } + } + } +} + +GLuint GLRenderer::loadShader(GLenum stage, const char* source) +{ + // GLSL is monumentally stupid. It officially requires the `#version` directive + // to be the first thing in the file, which wouldn't be so bad but the API + // doesn't provide a way to pass a `#define` into your shader other than by + // prepending it to the whole thing. + // + // We are going to solve this problem by doing some surgery on the source + // that was passed in. + + const char* sourceBegin = source; + const char* sourceEnd = source + strlen(source); + + // Look for a version directive in the user-provided source. + const char* versionBegin = strstr(source, "#version"); + const char* versionEnd = nullptr; + if (versionBegin) + { + // If we found a directive, then scan for the end-of-line + // after it, and use that to specify the slice. + versionEnd = strchr(versionBegin, '\n'); + if (!versionEnd) + { + versionEnd = sourceEnd; + } + else + { + versionEnd = versionEnd + 1; + } + } + else + { + // If we didn't find a directive, then treat it as being + // a zero-byte slice at the start of the string + versionBegin = sourceBegin; + versionEnd = sourceBegin; + } + + enum { kMaxSourceStringCount = 16 }; + const GLchar* sourceStrings[kMaxSourceStringCount]; + GLint sourceStringLengths[kMaxSourceStringCount]; + + int sourceStringCount = 0; + + const char* stagePrelude = "\n"; + switch (stage) + { +#define CASE(NAME) case GL_##NAME##_SHADER: stagePrelude = "#define __GLSL_" #NAME "__ 1\n"; break + + CASE(VERTEX); + CASE(TESS_CONTROL); + CASE(TESS_EVALUATION); + CASE(GEOMETRY); + CASE(FRAGMENT); + CASE(COMPUTE); + +#undef CASE + } + + const char* prelude = + "#define __GLSL__ 1\n" + ; + +#define ADD_SOURCE_STRING_SPAN(BEGIN, END) \ + sourceStrings[sourceStringCount] = BEGIN; \ + sourceStringLengths[sourceStringCount++] = GLint(END - BEGIN) \ + /* end */ + +#define ADD_SOURCE_STRING(BEGIN) \ + sourceStrings[sourceStringCount] = BEGIN; \ + sourceStringLengths[sourceStringCount++] = GLint(strlen(BEGIN)) \ + /* end */ + + ADD_SOURCE_STRING_SPAN(versionBegin, versionEnd); + ADD_SOURCE_STRING(stagePrelude); + ADD_SOURCE_STRING(prelude); + ADD_SOURCE_STRING_SPAN(sourceBegin, versionBegin); + ADD_SOURCE_STRING_SPAN(versionEnd, sourceEnd); + + auto shaderID = glCreateShader(stage); + glShaderSource( + shaderID, + sourceStringCount, + &sourceStrings[0], + &sourceStringLengths[0]); + glCompileShader(shaderID); + + GLint success = GL_FALSE; + glGetShaderiv(shaderID, GL_COMPILE_STATUS, &success); + if (!success) + { + int maxSize = 0; + glGetShaderiv(shaderID, GL_INFO_LOG_LENGTH, &maxSize); + + auto infoBuffer = (char*)malloc(maxSize); + + int infoSize = 0; + glGetShaderInfoLog(shaderID, maxSize, &infoSize, infoBuffer); + if (infoSize > 0) + { + fprintf(stderr, "%s", infoBuffer); + ::OutputDebugStringA(infoBuffer); + } + + glDeleteShader(shaderID); + return 0; + } + + return shaderID; +} + +#if 0 +void GLRenderer::destroyBindingEntries(const BindingState::Desc& desc, const BindingDetail* details) +{ + const auto& bindings = desc.m_bindings; + const int numBindings = int(bindings.Count()); + for (int i = 0; i < numBindings; ++i) + { + const auto& binding = bindings[i]; + const auto& detail = details[i]; + + if (binding.bindingType == BindingType::Sampler && detail.m_samplerHandle != 0) + { + glDeleteSamplers(1, &detail.m_samplerHandle); + } + } +} +#endif + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!! Renderer interface !!!!!!!!!!!!!!!!!!!!!!!!!! + +SlangResult GLRenderer::initialize(const Desc& desc, void* inWindowHandle) +{ + auto windowHandle = (HWND)inWindowHandle; + m_desc = desc; + + m_hdc = ::GetDC(windowHandle); + + PIXELFORMATDESCRIPTOR pixelFormatDesc = { sizeof(PIXELFORMATDESCRIPTOR) }; + pixelFormatDesc.nVersion = 1; + pixelFormatDesc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pixelFormatDesc.iPixelType = PFD_TYPE_RGBA; + pixelFormatDesc.cColorBits = 32; + pixelFormatDesc.cDepthBits = 24; + pixelFormatDesc.cStencilBits = 8; + pixelFormatDesc.iLayerType = PFD_MAIN_PLANE; + + int pixelFormatIndex = ChoosePixelFormat(m_hdc, &pixelFormatDesc); + SetPixelFormat(m_hdc, pixelFormatIndex, &pixelFormatDesc); + + m_glContext = wglCreateContext(m_hdc); + wglMakeCurrent(m_hdc, m_glContext); + + auto renderer = glGetString(GL_RENDERER); + + if (renderer && desc.adapter.getLength() > 0) + { + String lowerAdapter = desc.adapter.toLower(); + String lowerRenderer = String((const char*)renderer).toLower(); + + // The adapter is not available + if (lowerRenderer.indexOf(lowerAdapter) == Index(-1)) + { + return SLANG_E_NOT_AVAILABLE; + } + } + + auto extensions = glGetString(GL_EXTENSIONS); + + // Load each of our extension functions by name + +#define LOAD_GL_EXTENSION_FUNC(NAME, TYPE) NAME = (TYPE) wglGetProcAddress(#NAME); + MAP_GL_EXTENSION_FUNCS(LOAD_GL_EXTENSION_FUNC) +#undef LOAD_GL_EXTENSION_FUNC + + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + + glViewport(0, 0, desc.width, desc.height); + + if (glDebugMessageCallback) + { + glEnable(GL_DEBUG_OUTPUT); + glDebugMessageCallback(staticDebugCallback, this); + } + + return SLANG_OK; +} + +void GLRenderer::setClearColor(const float color[4]) +{ + glClearColor(color[0], color[1], color[2], color[3]); +} + +void GLRenderer::clearFrame() +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); +} + +void GLRenderer::presentFrame() +{ + glFlush(); + ::SwapBuffers(m_hdc); +} + +TextureResource::Desc GLRenderer::getSwapChainTextureDesc() +{ + TextureResource::Desc desc; + desc.init2D(Resource::Type::Texture2D, Format::Unknown, m_desc.width, m_desc.height, 1); + return desc; +} + +SlangResult GLRenderer::captureScreenSurface(Surface& surfaceOut) +{ + SLANG_RETURN_ON_FAIL(surfaceOut.allocate(m_desc.width, m_desc.height, Format::RGBA_Unorm_UInt8, 1, SurfaceAllocator::getMallocAllocator())); + glReadPixels(0, 0, m_desc.width, m_desc.height, GL_RGBA, GL_UNSIGNED_BYTE, surfaceOut.m_data); + surfaceOut.flipInplaceVertically(); + return SLANG_OK; +} + +Result GLRenderer::createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& descIn, const TextureResource::Data* initData, TextureResource** outResource) +{ + TextureResource::Desc srcDesc(descIn); + srcDesc.setDefaults(initialUsage); + + GlPixelFormat pixelFormat = _getGlPixelFormat(srcDesc.format); + if (pixelFormat == GlPixelFormat::Unknown) + { + return SLANG_FAIL; + } + + const GlPixelFormatInfo& info = s_pixelFormatInfos[int(pixelFormat)]; + + const GLint internalFormat = info.internalFormat; + const GLenum format = info.format; + const GLenum formatType = info.formatType; + + RefPtr<TextureResourceImpl> texture(new TextureResourceImpl(initialUsage, srcDesc, m_weakRenderer)); + + GLenum target = 0; + GLuint handle = 0; + glGenTextures(1, &handle); + + const int effectiveArraySize = srcDesc.calcEffectiveArraySize(); + + assert(initData); + assert(initData->numSubResources == srcDesc.numMipLevels * srcDesc.size.depth * effectiveArraySize); + + // Set on texture so will be freed if failure + texture->m_handle = handle; + const void*const*const data = initData->subResources; + + switch (srcDesc.type) + { + case Resource::Type::Texture1D: + { + if (srcDesc.arraySize > 0) + { + target = GL_TEXTURE_1D_ARRAY; + glBindTexture(target, handle); + + int slice = 0; + for (int i = 0; i < effectiveArraySize; i++) + { + for (int j = 0; j < srcDesc.numMipLevels; j++) + { + glTexImage2D(target, j, internalFormat, srcDesc.size.width, i, 0, format, formatType, data[slice++]); + } + } + } + else + { + target = GL_TEXTURE_1D; + glBindTexture(target, handle); + for (int i = 0; i < srcDesc.numMipLevels; i++) + { + glTexImage1D(target, i, internalFormat, srcDesc.size.width, 0, format, formatType, data[i]); + } + } + break; + } + case Resource::Type::TextureCube: + case Resource::Type::Texture2D: + { + if (srcDesc.arraySize > 0) + { + if (srcDesc.type == Resource::Type::TextureCube) + { + target = GL_TEXTURE_CUBE_MAP_ARRAY; + } + else + { + target = GL_TEXTURE_2D_ARRAY; + } + + glBindTexture(target, handle); + + int slice = 0; + for (int i = 0; i < effectiveArraySize; i++) + { + for (int j = 0; j < srcDesc.numMipLevels; j++) + { + glTexImage3D(target, j, internalFormat, srcDesc.size.width, srcDesc.size.height, slice, 0, format, formatType, data[slice++]); + } + } + } + else + { + if (srcDesc.type == Resource::Type::TextureCube) + { + target = GL_TEXTURE_CUBE_MAP; + glBindTexture(target, handle); + + int slice = 0; + for (int j = 0; j < 6; j++) + { + for (int i = 0; i < srcDesc.numMipLevels; i++) + { + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + j, i, internalFormat, srcDesc.size.width, srcDesc.size.height, 0, format, formatType, data[slice++]); + } + } + } + else + { + target = GL_TEXTURE_2D; + glBindTexture(target, handle); + for (int i = 0; i < srcDesc.numMipLevels; i++) + { + glTexImage2D(target, i, internalFormat, srcDesc.size.width, srcDesc.size.height, 0, format, formatType, data[i]); + } + } + } + break; + } + case Resource::Type::Texture3D: + { + target = GL_TEXTURE_3D; + glBindTexture(target, handle); + for (int i = 0; i < srcDesc.numMipLevels; i++) + { + glTexImage3D(target, i, internalFormat, srcDesc.size.width, srcDesc.size.height, srcDesc.size.depth, 0, format, formatType, data[i]); + } + break; + } + default: + return SLANG_FAIL; + } + + glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_REPEAT); + + // Assume regular sampling (might be superseded - if a combined sampler wanted) + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8.0f); + + texture->m_target = target; + + *outResource = texture.detach(); + return SLANG_OK; +} + +static GLenum _calcUsage(Resource::Usage usage) +{ + typedef Resource::Usage Usage; + switch (usage) + { + case Usage::ConstantBuffer: return GL_DYNAMIC_DRAW; + default: return GL_STATIC_READ; + } +} + +static GLenum _calcTarget(Resource::Usage usage) +{ + typedef Resource::Usage Usage; + switch (usage) + { + case Usage::ConstantBuffer: return GL_UNIFORM_BUFFER; + default: return GL_SHADER_STORAGE_BUFFER; + } +} + +Result GLRenderer::createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& descIn, const void* initData, BufferResource** outResource) +{ + BufferResource::Desc desc(descIn); + desc.setDefaults(initialUsage); + + const GLenum target = _calcTarget(initialUsage); + // TODO: should derive from desc... + const GLenum usage = _calcUsage(initialUsage); + + GLuint bufferID = 0; + glGenBuffers(1, &bufferID); + glBindBuffer(target, bufferID); + + glBufferData(target, descIn.sizeInBytes, initData, usage); + + RefPtr<BufferResourceImpl> resourceImpl = new BufferResourceImpl(initialUsage, desc, m_weakRenderer, bufferID, target); + *outResource = resourceImpl.detach(); + return SLANG_OK; +} + +Result GLRenderer::createSamplerState(SamplerState::Desc const& desc, SamplerState** outSampler) +{ + GLuint samplerID; + glCreateSamplers(1, &samplerID); + + RefPtr<SamplerStateImpl> samplerImpl = new SamplerStateImpl(); + samplerImpl->m_samplerID = samplerID; + *outSampler = samplerImpl.detach(); + return SLANG_OK; +} + +Result GLRenderer::createTextureView(TextureResource* texture, ResourceView::Desc const& desc, ResourceView** outView) +{ + auto resourceImpl = (TextureResourceImpl*) texture; + + // TODO: actually do something? + + RefPtr<TextureViewImpl> viewImpl = new TextureViewImpl(); + viewImpl->m_resource = resourceImpl; + viewImpl->m_textureID = resourceImpl->m_handle; + *outView = viewImpl; + return SLANG_OK; +} + +Result GLRenderer::createBufferView(BufferResource* buffer, ResourceView::Desc const& desc, ResourceView** outView) +{ + auto resourceImpl = (BufferResourceImpl*) buffer; + + // TODO: actually do something? + + RefPtr<BufferViewImpl> viewImpl = new BufferViewImpl(); + viewImpl->m_resource = resourceImpl; + viewImpl->m_bufferID = resourceImpl->m_handle; + *outView = viewImpl.detach(); + return SLANG_OK; +} + +Result GLRenderer::createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount, InputLayout** outLayout) +{ + RefPtr<InputLayoutImpl> inputLayout = new InputLayoutImpl; + + inputLayout->m_attributeCount = inputElementCount; + for (UInt ii = 0; ii < inputElementCount; ++ii) + { + auto& inputAttr = inputElements[ii]; + auto& glAttr = inputLayout->m_attributes[ii]; + + glAttr.streamIndex = 0; + glAttr.format = getVertexAttributeFormat(inputAttr.format); + glAttr.offset = (GLsizei)inputAttr.offset; + } + + *outLayout = inputLayout.detach(); + return SLANG_OK; +} + +void* GLRenderer::map(BufferResource* bufferIn, MapFlavor flavor) +{ + BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(bufferIn); + + //GLenum target = GL_UNIFORM_BUFFER; + + GLuint access = 0; + switch (flavor) + { + case MapFlavor::WriteDiscard: + case MapFlavor::HostWrite: + access = GL_WRITE_ONLY; + break; + case MapFlavor::HostRead: + access = GL_READ_ONLY; + break; + } + + glBindBuffer(buffer->m_target, buffer->m_handle); + + return glMapBuffer(buffer->m_target, access); +} + +void GLRenderer::unmap(BufferResource* bufferIn) +{ + BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(bufferIn); + glUnmapBuffer(buffer->m_target); +} + +void GLRenderer::setPrimitiveTopology(PrimitiveTopology topology) +{ + GLenum glTopology = 0; + switch (topology) + { +#define CASE(NAME, VALUE) case PrimitiveTopology::NAME: glTopology = VALUE; break + + CASE(TriangleList, GL_TRIANGLES); + +#undef CASE + } + m_boundPrimitiveTopology = glTopology; +} + +void GLRenderer::setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets) +{ + for (UInt ii = 0; ii < slotCount; ++ii) + { + UInt slot = startSlot + ii; + + BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(buffers[ii]); + GLuint bufferID = buffer ? buffer->m_handle : 0; + + m_boundVertexStreamBuffers[slot] = bufferID; + m_boundVertexStreamStrides[slot] = strides[ii]; + m_boundVertexStreamOffsets[slot] = offsets[ii]; + } +} + +void GLRenderer::setIndexBuffer(BufferResource* buffer, Format indexFormat, UInt offset) +{ +} + +void GLRenderer::setDepthStencilTarget(ResourceView* depthStencilView) +{ +} + +void GLRenderer::setViewports(UInt count, Viewport const* viewports) +{ + assert(count == 1); + auto viewport = viewports[0]; + glViewport( + (GLint) viewport.originX, + (GLint) viewport.originY, + (GLsizei) viewport.extentX, + (GLsizei) viewport.extentY); + glDepthRange(viewport.minZ, viewport.maxZ); +} + +void GLRenderer::setScissorRects(UInt count, ScissorRect const* rects) +{ + assert(count <= 1); + if( count ) + { + // TODO: this isn't goign to be quite right because of the + // flipped coordinate system in GL. + // + // The best way around this is probably to *always* render + // things internally into textures with "flipped" conventions, + // and then only deal with the flipping as part of a final + // "present" step that copies to the primary back-buffer. + // + auto rect = rects[0]; + glScissor( + GLint(rect.minX), + GLint(rect.minY), + GLsizei(rect.maxX - rect.minX), + GLsizei(rect.maxY - rect.minY)); + + glEnable(GL_SCISSOR_TEST); + } + else + { + glDisable(GL_SCISSOR_TEST); + } +} + +void GLRenderer::setPipelineState(PipelineType pipelineType, PipelineState* state) +{ + auto pipelineStateImpl = (PipelineStateImpl*) state; + + m_currentPipelineState = pipelineStateImpl; + + auto program = pipelineStateImpl->m_program; + GLuint programID = program ? program->m_id : 0; + glUseProgram(programID); +} + +void GLRenderer::draw(UInt vertexCount, UInt startVertex = 0) +{ + flushStateForDraw(); + + glDrawArrays(m_boundPrimitiveTopology, (GLint)startVertex, (GLsizei)vertexCount); +} + +void GLRenderer::drawIndexed(UInt indexCount, UInt startIndex, UInt baseVertex) +{ + assert(!"unimplemented"); +} + +void GLRenderer::dispatchCompute(int x, int y, int z) +{ + glDispatchCompute(x, y, z); +} + +#if 0 +BindingState* GLRenderer::createBindingState(const BindingState::Desc& bindingStateDesc) +{ + RefPtr<BindingStateImpl> bindingState(new BindingStateImpl(bindingStateDesc, this)); + + const auto& srcBindings = bindingStateDesc.m_bindings; + const int numBindings = int(srcBindings.Count()); + + auto& dstDetails = bindingState->m_bindingDetails; + dstDetails.SetSize(numBindings); + + for (int i = 0; i < numBindings; ++i) + { + auto& dstDetail = dstDetails[i]; + const auto& srcBinding = srcBindings[i]; + + + switch (srcBinding.bindingType) + { + case BindingType::Texture: + case BindingType::Buffer: + { + break; + } + case BindingType::CombinedTextureSampler: + { + assert(srcBinding.resource && srcBinding.resource->isTexture()); + TextureResourceImpl* texture = static_cast<TextureResourceImpl*>(srcBinding.resource.Ptr()); + const BindingState::SamplerDesc& samplerDesc = bindingStateDesc.m_samplerDescs[srcBinding.descIndex]; + + if (samplerDesc.isCompareSampler) + { + auto target = texture->m_target; + + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); + glTexParameteri(target, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + } + break; + } + case BindingType::Sampler: + { + const BindingState::SamplerDesc& samplerDesc = bindingStateDesc.m_samplerDescs[srcBinding.descIndex]; + + GLuint handle; + + glCreateSamplers(1, &handle); + glSamplerParameteri(handle, GL_TEXTURE_WRAP_S, GL_REPEAT); + glSamplerParameteri(handle, GL_TEXTURE_WRAP_T, GL_REPEAT); + glSamplerParameteri(handle, GL_TEXTURE_WRAP_R, GL_REPEAT); + + if (samplerDesc.isCompareSampler) + { + glSamplerParameteri(handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glSamplerParameteri(handle, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glSamplerParameteri(handle, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); + glSamplerParameteri(handle, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + } + else + { + glSamplerParameteri(handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glSamplerParameteri(handle, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glSamplerParameteri(handle, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8); + } + + dstDetail.m_samplerHandle = handle; + break; + } + } + } + + return bindingState.detach(); +} + +void GLRenderer::setBindingState(BindingState* stateIn) +{ + BindingStateImpl* state = static_cast<BindingStateImpl*>(stateIn); + + const auto& bindingDesc = state->getDesc(); + + const auto& details = state->m_bindingDetails; + const auto& bindings = bindingDesc.m_bindings; + const int numBindings = int(bindings.Count()); + + for (int i = 0; i < numBindings; ++i) + { + const auto& binding = bindings[i]; + const auto& detail = details[i]; + + switch (binding.bindingType) + { + case BindingType::Buffer: + { + const int bindingIndex = binding.registerRange.getSingleIndex(); + + BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(binding.resource.Ptr()); + glBindBufferBase(buffer->m_target, bindingIndex, buffer->m_handle); + break; + } + case BindingType::Sampler: + { + for (int index = binding.registerRange.index; index < binding.registerRange.index + binding.registerRange.size; ++index) + { + glBindSampler(index, detail.m_samplerHandle); + } + break; + } + case BindingType::Texture: + case BindingType::CombinedTextureSampler: + { + BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(binding.resource.Ptr()); + + const int bindingIndex = binding.registerRange.getSingleIndex(); + + glActiveTexture(GL_TEXTURE0 + bindingIndex); + glBindTexture(buffer->m_target, buffer->m_handle); + break; + } + } + } +} +#endif + +void GLRenderer::DescriptorSetImpl::setConstantBuffer(UInt range, UInt index, BufferResource* buffer) +{ + auto resourceImpl = (BufferResourceImpl*) buffer; + + auto layout = m_layout; + auto rangeInfo = layout->m_ranges[range]; + auto arrayIndex = rangeInfo.arrayIndex + index; + + m_constantBuffers[arrayIndex] = resourceImpl; +} + +void GLRenderer::DescriptorSetImpl::setResource(UInt range, UInt index, ResourceView* view) +{ + auto viewImpl = (ResourceViewImpl*) view; + + auto layout = m_layout; + auto rangeInfo = layout->m_ranges[range]; + auto arrayIndex = rangeInfo.arrayIndex + index; + + assert(!"unimplemented"); +} + +void GLRenderer::DescriptorSetImpl::setSampler(UInt range, UInt index, SamplerState* sampler) +{ + assert(!"unsupported"); +} + +void GLRenderer::DescriptorSetImpl::setCombinedTextureSampler( + UInt range, + UInt index, + ResourceView* textureView, + SamplerState* sampler) +{ + auto viewImpl = (TextureViewImpl*) textureView; + auto samplerImpl = (SamplerStateImpl*) sampler; + + auto layout = m_layout; + auto rangeInfo = layout->m_ranges[range]; + auto arrayIndex = rangeInfo.arrayIndex + index; + + m_textures[arrayIndex] = viewImpl; + m_samplers[arrayIndex] = samplerImpl; +} + +void GLRenderer::setDescriptorSet(PipelineType pipelineType, PipelineLayout* layout, UInt index, DescriptorSet* descriptorSet) +{ + auto descriptorSetImpl = (DescriptorSetImpl*)descriptorSet; + + // TODO: can we just bind things immediately here, rather than shadowing the state? + + m_boundDescriptorSets[index] = descriptorSetImpl; +} + +Result GLRenderer::createDescriptorSetLayout(const DescriptorSetLayout::Desc& desc, DescriptorSetLayout** outLayout) +{ + RefPtr<DescriptorSetLayoutImpl> layoutImpl = new DescriptorSetLayoutImpl(); + + Int counts[int(GLDescriptorSlotType::CountOf)] = { 0, }; + + Int rangeCount = desc.slotRangeCount; + for(Int rr = 0; rr < rangeCount; ++rr) + { + auto rangeDesc = desc.slotRanges[rr]; + DescriptorSetLayoutImpl::RangeInfo rangeInfo; + + GLDescriptorSlotType glSlotType; + switch( rangeDesc.type ) + { + default: + assert(!"unsupported"); + break; + + // TODO: There are many other slot types we could support here, + // in particular including storage buffers. + + case DescriptorSlotType::CombinedImageSampler: + glSlotType = GLDescriptorSlotType::CombinedTextureSampler; + break; + + case DescriptorSlotType::UniformBuffer: + case DescriptorSlotType::DynamicUniformBuffer: + glSlotType = GLDescriptorSlotType::ConstantBuffer; + break; + } + + rangeInfo.type = glSlotType; + rangeInfo.arrayIndex = counts[int(glSlotType)]; + counts[int(glSlotType)] += rangeDesc.count; + + layoutImpl->m_ranges.add(rangeInfo); + } + + for( Int ii = 0; ii < int(GLDescriptorSlotType::CountOf); ++ii ) + { + layoutImpl->m_counts[ii] = counts[ii]; + } + + *outLayout = layoutImpl.detach(); + return SLANG_OK; +} + +Result GLRenderer::createPipelineLayout(const PipelineLayout::Desc& desc, PipelineLayout** outLayout) +{ + RefPtr<PipelineLayoutImpl> layoutImpl = new PipelineLayoutImpl(); + + static const int kSlotTypeCount = int(GLDescriptorSlotType::CountOf); + Int counts[kSlotTypeCount] = { 0, }; + + Int setCount = desc.descriptorSetCount; + for( Int ii = 0; ii < setCount; ++ii ) + { + auto setLayout = (DescriptorSetLayoutImpl*) desc.descriptorSets[ii].layout; + + PipelineLayoutImpl::DescriptorSetInfo setInfo; + setInfo.layout = setLayout; + + for( Int ii = 0; ii < int(GLDescriptorSlotType::CountOf); ++ii ) + { + setInfo.baseArrayIndex[ii] = counts[ii]; + counts[ii] += setLayout->m_counts[ii]; + } + + layoutImpl->m_sets.add(setInfo); + } + + *outLayout = layoutImpl.detach(); + return SLANG_OK; +} + +Result GLRenderer::createDescriptorSet(DescriptorSetLayout* layout, DescriptorSet** outDescriptorSet) +{ + auto layoutImpl = (DescriptorSetLayoutImpl*) layout; + + RefPtr<DescriptorSetImpl> descriptorSetImpl = new DescriptorSetImpl(); + + descriptorSetImpl->m_layout = layoutImpl; + + // TODO: storage for the arrays of bound objects could be tail allocated + // as part of the descriptor set, with offsets pre-computed in the + // descriptor set layout. + + { + auto slotTypeIndex = int(GLDescriptorSlotType::ConstantBuffer); + auto slotCount = layoutImpl->m_counts[slotTypeIndex]; + descriptorSetImpl->m_constantBuffers.setCount(slotCount); + } + + { + auto slotTypeIndex = int(GLDescriptorSlotType::CombinedTextureSampler); + auto slotCount = layoutImpl->m_counts[slotTypeIndex]; + + descriptorSetImpl->m_textures.setCount(slotCount); + descriptorSetImpl->m_samplers.setCount(slotCount); + } + + *outDescriptorSet = descriptorSetImpl.detach(); + return SLANG_OK; +} + +Result GLRenderer::createProgram(const ShaderProgram::Desc& desc, ShaderProgram** outProgram) +{ + auto programID = glCreateProgram(); + if(desc.pipelineType == PipelineType::Compute ) + { + auto computeKernel = desc.findKernel(StageType::Compute); + auto computeShaderID = loadShader(GL_COMPUTE_SHADER, (char const*) computeKernel->codeBegin); + glAttachShader(programID, computeShaderID); + glLinkProgram(programID); + glDeleteShader(computeShaderID); + } + else + { + auto vertexKernel = desc.findKernel(StageType::Vertex); + auto fragmentKernel = desc.findKernel(StageType::Fragment); + + auto vertexShaderID = loadShader(GL_VERTEX_SHADER, (char const*) vertexKernel->codeBegin); + auto fragmentShaderID = loadShader(GL_FRAGMENT_SHADER, (char const*) fragmentKernel->codeBegin); + + glAttachShader(programID, vertexShaderID); + glAttachShader(programID, fragmentShaderID); + + + glLinkProgram(programID); + + glDeleteShader(vertexShaderID); + glDeleteShader(fragmentShaderID); + } + GLint success = GL_FALSE; + glGetProgramiv(programID, GL_LINK_STATUS, &success); + if (!success) + { + int maxSize = 0; + glGetProgramiv(programID, GL_INFO_LOG_LENGTH, &maxSize); + + auto infoBuffer = (char*)::malloc(maxSize); + + int infoSize = 0; + glGetProgramInfoLog(programID, maxSize, &infoSize, infoBuffer); + if (infoSize > 0) + { + fprintf(stderr, "%s", infoBuffer); + OutputDebugStringA(infoBuffer); + } + + ::free(infoBuffer); + + glDeleteProgram(programID); + return SLANG_FAIL; + } + + *outProgram = new ShaderProgramImpl(m_weakRenderer, programID); + return SLANG_OK; +} + +Result GLRenderer::createGraphicsPipelineState(const GraphicsPipelineStateDesc& desc, PipelineState** outState) +{ + auto programImpl = (ShaderProgramImpl*) desc.program; + auto pipelineLayoutImpl = (PipelineLayoutImpl*) desc.pipelineLayout; + auto inputLayoutImpl = (InputLayoutImpl*) desc.inputLayout; + + RefPtr<PipelineStateImpl> pipelineStateImpl = new PipelineStateImpl(); + pipelineStateImpl->m_program = programImpl; + pipelineStateImpl->m_pipelineLayout = pipelineLayoutImpl; + pipelineStateImpl->m_inputLayout = inputLayoutImpl; + *outState = pipelineStateImpl.detach(); + return SLANG_OK; +} + +Result GLRenderer::createComputePipelineState(const ComputePipelineStateDesc& desc, PipelineState** outState) +{ + auto programImpl = (ShaderProgramImpl*) desc.program; + auto pipelineLayoutImpl = (PipelineLayoutImpl*) desc.pipelineLayout; + + RefPtr<PipelineStateImpl> pipelineStateImpl = new PipelineStateImpl(); + pipelineStateImpl->m_program = programImpl; + pipelineStateImpl->m_pipelineLayout = pipelineLayoutImpl; + *outState = pipelineStateImpl.detach(); + return SLANG_OK; +} + + +} // renderer_test |
