summaryrefslogtreecommitdiff
path: root/tools/slang-graphics/render-gl.cpp
diff options
context:
space:
mode:
authorTim Foley <tfoleyNV@users.noreply.github.com>2018-08-03 08:39:28 -0700
committerGitHub <noreply@github.com>2018-08-03 08:39:28 -0700
commit68d705f6c805c9b4d31b386e065762e6db13ad18 (patch)
tree97ffc0f24358101222d1bc62ac0c50affc55af12 /tools/slang-graphics/render-gl.cpp
parent5ea746a571ced32a8975eb3a238c562b3d487149 (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/slang-graphics/render-gl.cpp')
-rw-r--r--tools/slang-graphics/render-gl.cpp1049
1 files changed, 0 insertions, 1049 deletions
diff --git a/tools/slang-graphics/render-gl.cpp b/tools/slang-graphics/render-gl.cpp
deleted file mode 100644
index f85a81ca4..000000000
--- a/tools/slang-graphics/render-gl.cpp
+++ /dev/null
@@ -1,1049 +0,0 @@
-// render-gl.cpp
-#include "render-gl.h"
-
-//WORKING:#include "options.h"
-#include "render.h"
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include "core/basic.h"
-#include "core/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 slang_graphics {
-
-class GLRenderer : public Renderer
-{
-public:
-
- // Renderer implementation
- virtual SlangResult initialize(const Desc& desc, void* inWindowHandle) override;
- virtual void setClearColor(const float color[4]) override;
- virtual void clearFrame() override;
- virtual void presentFrame() override;
- virtual TextureResource* createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& desc, const TextureResource::Data* initData) override;
- virtual BufferResource* createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& descIn, const void* initData) override;
- virtual SlangResult captureScreenSurface(Surface& surfaceOut) override;
- virtual InputLayout* createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount) override;
- virtual BindingState* createBindingState(const BindingState::Desc& bindingStateDesc) override;
- virtual ShaderProgram* createProgram(const ShaderProgram::Desc& desc) override;
- virtual void* map(BufferResource* buffer, MapFlavor flavor) override;
- virtual void unmap(BufferResource* buffer) override;
- virtual void setInputLayout(InputLayout* inputLayout) override;
- virtual void setPrimitiveTopology(PrimitiveTopology topology) override;
- virtual void setBindingState(BindingState* state);
- virtual void setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets) override;
- virtual void setShaderProgram(ShaderProgram* inProgram) override;
- virtual void draw(UInt vertexCount, UInt startVertex) 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; }
-
- protected:
- enum
- {
- kMaxVertexStreams = 16,
- };
-
- 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, GLRenderer* renderer, GLuint id, GLenum target):
- Parent(desc),
- m_renderer(renderer),
- m_handle(id),
- m_initialUsage(initialUsage),
- m_target(target)
- {}
- ~BufferResourceImpl()
- {
- if (m_renderer)
- {
- m_renderer->glDeleteBuffers(1, &m_handle);
- }
- }
-
- Usage m_initialUsage;
- GLRenderer* m_renderer;
- GLuint m_handle;
- GLenum m_target;
- };
-
- class TextureResourceImpl: public TextureResource
- {
- public:
- typedef TextureResource Parent;
-
- TextureResourceImpl(Usage initialUsage, const Desc& desc, 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;
- GLRenderer* m_renderer;
- GLenum m_target;
- GLuint m_handle;
- };
-
- struct BindingDetail
- {
- GLuint m_samplerHandle = 0;
- };
-
- class BindingStateImpl: public BindingState
- {
- public:
- typedef BindingState Parent;
-
- /// Ctor
- BindingStateImpl(const Desc& desc, GLRenderer* renderer):
- Parent(desc),
- m_renderer(renderer)
- {
- }
-
- ~BindingStateImpl()
- {
- if (m_renderer)
- {
- m_renderer->destroyBindingEntries(getDesc(), m_bindingDetails.Buffer());
- }
- }
-
- GLRenderer* m_renderer;
- List<BindingDetail> m_bindingDetails;
- };
-
- class ShaderProgramImpl : public ShaderProgram
- {
- public:
- ShaderProgramImpl(GLRenderer* renderer, GLuint id):
- m_renderer(renderer),
- m_id(id)
- {
- }
- ~ShaderProgramImpl()
- {
- if (m_renderer)
- {
- m_renderer->glDeleteProgram(m_id);
- }
- }
-
- GLuint m_id;
- GLRenderer* m_renderer;
- };
-
- 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<ShaderProgramImpl> m_boundShaderProgram;
- RefPtr<InputLayoutImpl> m_boundInputLayout;
-
- GLenum m_boundPrimitiveTopology = GL_TRIANGLES;
- GLuint m_boundVertexStreamBuffers[kMaxVertexStreams];
- UInt m_boundVertexStreamStrides[kMaxVertexStreams];
- UInt m_boundVertexStreamOffsets[kMaxVertexStreams];
-
- Desc m_desc;
-
- // 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;
- }
-}
-
-/* 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 layout = m_boundInputLayout.Ptr();
- auto attrCount = layout->m_attributeCount;
- for (UInt ii = 0; ii < attrCount; ++ii)
- {
- auto& attr = layout->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 (UInt ii = attrCount; ii < kMaxVertexStreams; ++ii)
- {
- glDisableVertexAttribArray((GLuint)ii);
- }
-}
-
-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;
-}
-
-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);
- }
- }
-}
-
-// !!!!!!!!!!!!!!!!!!!!!!!!!!!! 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);
- 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);
-}
-
-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;
-}
-
-TextureResource* GLRenderer::createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& descIn, const TextureResource::Data* initData)
-{
- TextureResource::Desc srcDesc(descIn);
- srcDesc.setDefaults(initialUsage);
-
- GlPixelFormat pixelFormat = _getGlPixelFormat(srcDesc.format);
- if (pixelFormat == GlPixelFormat::Unknown)
- {
- return nullptr;
- }
-
- 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, this));
-
- 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 nullptr;
- }
-
- 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;
-
- return texture.detach();
-}
-
-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;
- }
-}
-
-BufferResource* GLRenderer::createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& descIn, const void* initData)
-{
- 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);
-
- return new BufferResourceImpl(initialUsage, desc, this, bufferID, target);
-}
-
-InputLayout* GLRenderer::createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount)
-{
- 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;
- }
-
- return (InputLayout*)inputLayout;
-}
-
-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::setInputLayout(InputLayout* inputLayout)
-{
- m_boundInputLayout = static_cast<InputLayoutImpl*>(inputLayout);
-}
-
-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::setShaderProgram(ShaderProgram* programIn)
-{
- ShaderProgramImpl* program = static_cast<ShaderProgramImpl*>(programIn);
- m_boundShaderProgram = 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::dispatchCompute(int x, int y, int z)
-{
- glDispatchCompute(x, y, z);
-}
-
-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;
- }
- }
- }
-}
-
-ShaderProgram* GLRenderer::createProgram(const ShaderProgram::Desc& desc)
-{
- 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 nullptr;
- }
-
- return new ShaderProgramImpl(this, programID);
-}
-
-
-} // renderer_test