yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

Jay KwakFix compiler warning with clang 18.1.8 on windows (#6843)04db5a956

master
110.5 KiB3174 linesraw
1// render-gl.cpp
2#include "render-gl.h"
3
4#include "../immediate-renderer-base.h"
5#include "../mutable-shader-object.h"
6#include "../nvapi/nvapi-util.h"
7#include "core/slang-basic.h"
8#include "core/slang-blob.h"
9#include "core/slang-secure-crt.h"
10#include "stb_image_write.h"
11
12#if SLANG_WIN64 || SLANG_WIN64
13#define ENABLE_GL_IMPL 1
14#else
15#define ENABLE_GL_IMPL 0
16#endif
17
18#if ENABLE_GL_IMPL
19
20// TODO(tfoley): eventually we should be able to run these
21// tests on non-Windows targets to confirm that cross-compilation
22// at least *works* on those platforms...
23
24#include <windows.h>
25
26#ifdef _MSC_VER
27#include <stddef.h>
28#if (_MSC_VER < 1900)
29#define snprintf sprintf_s
30#endif
31#endif
32
33#pragma comment(lib, "opengl32")
34
35// clang-format off
36#    include <GL/GL.h>
37#    include "external/glext.h"
38#    include "external/wglext.h"
39// clang-format on
40
41// We define an "X-macro" for mapping over loadable OpenGL
42// extension entry point that we will use, so that we can
43// easily write generic code to iterate over them.
44#define MAP_GL_EXTENSION_FUNCS(F)                                    \
45    F(glCreateProgram, PFNGLCREATEPROGRAMPROC)                       \
46    F(glCreateShader, PFNGLCREATESHADERPROC)                         \
47    F(glShaderSource, PFNGLSHADERSOURCEPROC)                         \
48    F(glCompileShader, PFNGLCOMPILESHADERPROC)                       \
49    F(glGetShaderiv, PFNGLGETSHADERIVPROC)                           \
50    F(glDeleteShader, PFNGLDELETESHADERPROC)                         \
51    F(glAttachShader, PFNGLATTACHSHADERPROC)                         \
52    F(glLinkProgram, PFNGLLINKPROGRAMPROC)                           \
53    F(glGetProgramiv, PFNGLGETPROGRAMIVPROC)                         \
54    F(glGetProgramInfoLog, PFNGLGETPROGRAMINFOLOGPROC)               \
55    F(glDeleteProgram, PFNGLDELETEPROGRAMPROC)                       \
56    F(glGetShaderInfoLog, PFNGLGETSHADERINFOLOGPROC)                 \
57    F(glGenBuffers, PFNGLGENBUFFERSPROC)                             \
58    F(glBindBuffer, PFNGLBINDBUFFERPROC)                             \
59    F(glBufferData, PFNGLBUFFERDATAPROC)                             \
60    F(glCopyBufferSubData, PFNGLCOPYBUFFERSUBDATAPROC)               \
61    F(glDeleteBuffers, PFNGLDELETEBUFFERSPROC)                       \
62    F(glMapBuffer, PFNGLMAPBUFFERPROC)                               \
63    F(glUnmapBuffer, PFNGLUNMAPBUFFERPROC)                           \
64    F(glUseProgram, PFNGLUSEPROGRAMPROC)                             \
65    F(glBindBufferBase, PFNGLBINDBUFFERBASEPROC)                     \
66    F(glBindBufferRange, PFNGLBINDBUFFERRANGEPROC)                   \
67    F(glVertexAttribPointer, PFNGLVERTEXATTRIBPOINTERPROC)           \
68    F(glEnableVertexAttribArray, PFNGLENABLEVERTEXATTRIBARRAYPROC)   \
69    F(glDisableVertexAttribArray, PFNGLDISABLEVERTEXATTRIBARRAYPROC) \
70    F(glDebugMessageCallback, PFNGLDEBUGMESSAGECALLBACKPROC)         \
71    F(glDispatchCompute, PFNGLDISPATCHCOMPUTEPROC)                   \
72    F(glActiveTexture, PFNGLACTIVETEXTUREPROC)                       \
73    F(glCreateSamplers, PFNGLCREATESAMPLERSPROC)                     \
74    F(glDeleteSamplers, PFNGLDELETESAMPLERSPROC)                     \
75    F(glBindSampler, PFNGLBINDSAMPLERPROC)                           \
76    F(glTexImage3D, PFNGLTEXIMAGE3DPROC)                             \
77    F(glBindImageTexture, PFNGLBINDIMAGETEXTUREPROC)                 \
78    F(glSamplerParameteri, PFNGLSAMPLERPARAMETERIPROC)               \
79    F(glGenFramebuffers, PFNGLGENFRAMEBUFFERSPROC)                   \
80    F(glDeleteFramebuffers, PFNGLDELETEFRAMEBUFFERSPROC)             \
81    F(glBindFramebuffer, PFNGLBINDFRAMEBUFFERPROC)                   \
82    F(glDrawBuffers, PFNGLDRAWBUFFERSPROC)                           \
83    F(glFramebufferTexture2D, PFNGLFRAMEBUFFERTEXTURE2DPROC)         \
84    F(glFramebufferTextureLayer, PFNGLFRAMEBUFFERTEXTURELAYERPROC)   \
85    F(glBlitFramebuffer, PFNGLBLITFRAMEBUFFERPROC)                   \
86    F(glCheckFramebufferStatus, PFNGLCHECKFRAMEBUFFERSTATUSPROC)     \
87    F(glGenVertexArrays, PFNGLGENVERTEXARRAYSPROC)                   \
88    F(glBindVertexArray, PFNGLBINDVERTEXARRAYPROC)                   \
89    F(glDeleteVertexArrays, PFNGLDELETEVERTEXARRAYSPROC)             \
90    F(glDrawElementsBaseVertex, PFNGLDRAWELEMENTSBASEVERTEXPROC)     \
91    /* end */
92
93#define MAP_WGL_EXTENSION_FUNCS(F)                                   \
94    F(wglCreateContextAttribsARB, PFNWGLCREATECONTEXTATTRIBSARBPROC) \
95    /* end */
96using namespace Slang;
97
98namespace gfx
99{
100
101class GLDevice : public ImmediateRendererBase
102{
103public:
104    // Renderer    implementation
105    virtual SLANG_NO_THROW Result SLANG_MCALL initialize(const Desc& desc) override;
106    virtual void clearFrame(uint32_t mask, bool clearDepth, bool clearStencil) override;
107    virtual SLANG_NO_THROW Result SLANG_MCALL createSwapchain(
108        const ISwapchain::Desc& desc,
109        WindowHandle window,
110        ISwapchain** outSwapchain) override;
111    virtual SLANG_NO_THROW Result SLANG_MCALL createFramebufferLayout(
112        const IFramebufferLayout::Desc& desc,
113        IFramebufferLayout** outLayout) override;
114    virtual SLANG_NO_THROW Result SLANG_MCALL
115    createFramebuffer(const IFramebuffer::Desc& desc, IFramebuffer** outFramebuffer) override;
116    virtual void setFramebuffer(IFramebuffer* frameBuffer) override;
117    virtual void setStencilReference(uint32_t referenceValue) override;
118
119    virtual SLANG_NO_THROW Result SLANG_MCALL createTextureResource(
120        const ITextureResource::Desc& desc,
121        const ITextureResource::SubresourceData* initData,
122        ITextureResource** outResource) override;
123    virtual SLANG_NO_THROW Result SLANG_MCALL createBufferResource(
124        const IBufferResource::Desc& desc,
125        const void* initData,
126        IBufferResource** outResource) override;
127    virtual SLANG_NO_THROW Result SLANG_MCALL
128    createSamplerState(ISamplerState::Desc const& desc, ISamplerState** outSampler) override;
129
130    virtual SLANG_NO_THROW Result SLANG_MCALL createTextureView(
131        ITextureResource* texture,
132        IResourceView::Desc const& desc,
133        IResourceView** outView) override;
134    virtual SLANG_NO_THROW Result SLANG_MCALL createBufferView(
135        IBufferResource* buffer,
136        IBufferResource* counterBuffer,
137        IResourceView::Desc const& desc,
138        IResourceView** outView) override;
139
140    virtual SLANG_NO_THROW Result SLANG_MCALL
141    createInputLayout(IInputLayout::Desc const& desc, IInputLayout** outLayout) override;
142
143    virtual Result createShaderObjectLayout(
144        slang::ISession* session,
145        slang::TypeLayoutReflection* typeLayout,
146        ShaderObjectLayoutBase** outLayout) override;
147    virtual Result createShaderObject(ShaderObjectLayoutBase* layout, IShaderObject** outObject)
148        override;
149    virtual Result createMutableShaderObject(
150        ShaderObjectLayoutBase* layout,
151        IShaderObject** outObject) override;
152    virtual Result createRootShaderObject(IShaderProgram* program, ShaderObjectBase** outObject)
153        override;
154    virtual void bindRootShaderObject(IShaderObject* shaderObject) override;
155
156    virtual SLANG_NO_THROW Result SLANG_MCALL createProgram(
157        const IShaderProgram::Desc& desc,
158        IShaderProgram** outProgram,
159        ISlangBlob** outDiagnosticBlob) override;
160    virtual SLANG_NO_THROW Result SLANG_MCALL createGraphicsPipelineState(
161        const GraphicsPipelineStateDesc& desc,
162        IPipelineState** outState) override;
163    virtual SLANG_NO_THROW Result SLANG_MCALL createComputePipelineState(
164        const ComputePipelineStateDesc& desc,
165        IPipelineState** outState) override;
166
167    virtual void copyBuffer(
168        IBufferResource* dst,
169        size_t dstOffset,
170        IBufferResource* src,
171        size_t srcOffset,
172        size_t size) override;
173    virtual SLANG_NO_THROW Result SLANG_MCALL readTextureResource(
174        ITextureResource* texture,
175        ResourceState state,
176        ISlangBlob** outBlob,
177        size_t* outRowPitch,
178        size_t* outPixelSize) override;
179
180    virtual void* map(IBufferResource* buffer, MapFlavor flavor) override;
181    virtual void unmap(IBufferResource* buffer, size_t offsetWritten, size_t sizeWritten) override;
182    virtual void setPrimitiveTopology(PrimitiveTopology topology) override;
183
184    virtual void setVertexBuffers(
185        GfxIndex startSlot,
186        GfxCount slotCount,
187        IBufferResource* const* buffers,
188        const Offset* offsets) override;
189    virtual void setIndexBuffer(IBufferResource* buffer, Format indexFormat, Offset offset)
190        override;
191    virtual void setViewports(GfxCount count, Viewport const* viewports) override;
192    virtual void setScissorRects(GfxCount count, ScissorRect const* rects) override;
193    virtual void setPipelineState(IPipelineState* state) override;
194    virtual void draw(GfxCount vertexCount, GfxCount startVertex) override;
195    virtual void drawIndexed(GfxCount indexCount, GfxIndex startIndex, GfxIndex baseVertex)
196        override;
197    virtual void drawInstanced(
198        GfxCount vertexCount,
199        GfxCount instanceCount,
200        GfxIndex startVertex,
201        GfxIndex startInstanceLocation) override;
202    virtual void drawIndexedInstanced(
203        GfxCount indexCount,
204        GfxCount instanceCount,
205        GfxIndex startIndexLocation,
206        GfxIndex baseVertexLocation,
207        GfxIndex startInstanceLocation) override;
208    virtual void dispatchCompute(int x, int y, int z) override;
209    virtual void submitGpuWork() override {}
210    virtual void waitForGpu() override {}
211    virtual void writeTimestamp(IQueryPool* pool, GfxIndex index) override
212    {
213        SLANG_UNUSED(pool);
214        SLANG_UNUSED(index);
215    }
216    virtual SLANG_NO_THROW Result SLANG_MCALL
217    createQueryPool(const IQueryPool::Desc& desc, IQueryPool** pool) override
218    {
219        SLANG_UNUSED(desc);
220        *pool = nullptr;
221        return SLANG_E_NOT_IMPLEMENTED;
222    }
223    virtual SLANG_NO_THROW const DeviceInfo& SLANG_MCALL getDeviceInfo() const override
224    {
225        return m_info;
226    }
227
228    HGLRC createGLContext(HDC hdc);
229    GLDevice();
230    ~GLDevice();
231
232protected:
233    enum
234    {
235        kMaxVertexAttributes = 16,
236        kMaxVertexStreams = 16,
237        kMaxDescriptorSetCount = 8,
238    };
239    struct VertexAttributeFormat
240    {
241        GLint componentCount;
242        GLenum componentType;
243        GLboolean normalized;
244    };
245
246    struct VertexAttributeDesc
247    {
248        VertexAttributeFormat format;
249        GLuint streamIndex;
250        GLsizei offset;
251    };
252
253    class InputLayoutImpl : public InputLayoutBase
254    {
255    public:
256        VertexAttributeDesc m_attributes[kMaxVertexAttributes];
257        VertexStreamDesc m_streams[kMaxVertexStreams];
258        UInt m_attributeCount = 0;
259        UInt m_streamCount = 0;
260    };
261
262    class BufferResourceImpl : public BufferResource
263    {
264    public:
265        typedef BufferResource Parent;
266
267        BufferResourceImpl(const Desc& desc, WeakSink<GLDevice>* renderer, GLuint id, GLenum target)
268            : Parent(desc)
269            , m_renderer(renderer)
270            , m_handle(id)
271            , m_target(target)
272            , m_size(desc.sizeInBytes)
273        {
274        }
275        ~BufferResourceImpl()
276        {
277            if (auto renderer = m_renderer->get())
278            {
279                renderer->glDeleteBuffers(1, &m_handle);
280            }
281        }
282
283        RefPtr<WeakSink<GLDevice>> m_renderer;
284        GLuint m_handle;
285        GLenum m_target;
286        UInt m_size;
287
288        virtual SLANG_NO_THROW DeviceAddress SLANG_MCALL getDeviceAddress() override { return 0; }
289
290        virtual SLANG_NO_THROW Result SLANG_MCALL
291        map(MemoryRange* rangeToRead, void** outPointer) override
292        {
293            SLANG_UNUSED(rangeToRead);
294            SLANG_UNUSED(outPointer);
295            return SLANG_FAIL;
296        }
297
298        virtual SLANG_NO_THROW Result SLANG_MCALL unmap(MemoryRange* writtenRange) override
299        {
300            SLANG_UNUSED(writtenRange);
301            return SLANG_FAIL;
302        }
303    };
304
305    class TextureResourceImpl : public TextureResource
306    {
307    public:
308        typedef TextureResource Parent;
309
310        TextureResourceImpl(const Desc& desc, WeakSink<GLDevice>* renderer)
311            : Parent(desc), m_renderer(renderer)
312        {
313            m_target = 0;
314            m_handle = 0;
315        }
316
317        ~TextureResourceImpl()
318        {
319            if (m_handle)
320            {
321                glDeleteTextures(1, &m_handle);
322            }
323        }
324
325        RefPtr<WeakSink<GLDevice>> m_renderer;
326        GLenum m_target;
327        GLuint m_handle;
328    };
329
330    class SamplerStateImpl : public SamplerStateBase
331    {
332    public:
333        GLuint m_samplerID;
334    };
335
336    class ResourceViewImpl : public ResourceViewBase
337    {
338    public:
339        enum class Type
340        {
341            Texture,
342            Buffer
343        };
344        Type type;
345    };
346
347    class TextureViewImpl : public ResourceViewImpl
348    {
349    public:
350        RefPtr<TextureResourceImpl> m_resource;
351        GLuint m_textureID;
352        GLuint m_target;
353        enum class TextureViewType
354        {
355            Texture,
356            Image
357        };
358        TextureViewType textureViewType;
359        GLint level;
360        GLboolean layered;
361        GLint layer;
362        GLenum access;
363        GLenum format;
364    };
365
366    class BufferViewImpl : public ResourceViewImpl
367    {
368    public:
369        RefPtr<BufferResourceImpl> m_resource;
370        GLuint m_bufferID;
371    };
372
373    class FramebufferLayoutImpl : public FramebufferLayoutBase
374    {
375    public:
376        ShortList<IFramebufferLayout::TargetLayout> m_renderTargets;
377        bool m_hasDepthStencil = false;
378        IFramebufferLayout::TargetLayout m_depthStencil;
379    };
380
381    class FramebufferImpl : public FramebufferBase
382    {
383    public:
384        GLuint m_framebuffer;
385        ShortList<GLenum> m_drawBuffers;
386        RefPtr<WeakSink<GLDevice>> m_renderer;
387        ShortList<RefPtr<TextureViewImpl>> renderTargetViews;
388        RefPtr<TextureViewImpl> depthStencilView;
389        ShortList<ColorClearValue> m_colorClearValues;
390        bool m_sameClearValues = true;
391        DepthStencilClearValue m_depthStencilClearValue;
392
393        FramebufferImpl(WeakSink<GLDevice>* renderer)
394            : m_renderer(renderer)
395        {
396        }
397        ~FramebufferImpl()
398        {
399            if (auto renderer = m_renderer->get())
400            {
401                renderer->glDeleteFramebuffers(1, &m_framebuffer);
402            }
403        }
404        void createGLFramebuffer()
405        {
406            auto renderer = m_renderer->get();
407            renderer->glGenFramebuffers(1, &m_framebuffer);
408            renderer->glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
409            m_drawBuffers.clear();
410            m_colorClearValues.clear();
411            for (Index i = 0; i < renderTargetViews.getCount(); i++)
412            {
413                auto rtv = renderTargetViews[i].Ptr();
414                renderer->glFramebufferTexture2D(
415                    GL_FRAMEBUFFER,
416                    GL_COLOR_ATTACHMENT0 + (uint32_t)i,
417                    GL_TEXTURE_2D,
418                    rtv->m_textureID,
419                    0);
420                m_drawBuffers.add((GLenum)(GL_COLOR_ATTACHMENT0 + i));
421                if (rtv->m_resource->getDesc()->optimalClearValue)
422                {
423                    m_colorClearValues.add(rtv->m_resource->getDesc()->optimalClearValue->color);
424                }
425                else
426                {
427                    m_colorClearValues.add(ColorClearValue());
428                }
429            }
430            m_sameClearValues = true;
431            for (Index i = 1; i < m_colorClearValues.getCount() && m_sameClearValues; i++)
432            {
433                for (int j = 0; j < 4; j++)
434                {
435                    if (m_colorClearValues[i].floatValues[j] !=
436                        m_colorClearValues[0].floatValues[j])
437                    {
438                        m_sameClearValues = false;
439                        break;
440                    }
441                }
442            }
443            if (depthStencilView)
444            {
445                renderer->glFramebufferTexture2D(
446                    GL_FRAMEBUFFER,
447                    GL_DEPTH_ATTACHMENT,
448                    GL_TEXTURE_2D,
449                    depthStencilView->m_textureID,
450                    0);
451                if (depthStencilView->m_resource->getDesc()->optimalClearValue)
452                {
453                    m_depthStencilClearValue =
454                        depthStencilView->m_resource->getDesc()->optimalClearValue->depthStencil;
455                }
456            }
457            auto error = renderer->glCheckFramebufferStatus(GL_FRAMEBUFFER);
458            if (error != GL_FRAMEBUFFER_COMPLETE)
459            {
460                return;
461            }
462        }
463    };
464
465    class SwapchainImpl : public ISwapchain, public ComObject
466    {
467    public:
468        SLANG_COM_OBJECT_IUNKNOWN_ALL
469        ISwapchain* getInterface(const Guid& guid)
470        {
471            if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_ISwapchain)
472                return static_cast<ISwapchain*>(this);
473            return nullptr;
474        }
475
476    public:
477        ~SwapchainImpl()
478        {
479            destroyBackBufferAndFBO();
480            wglDeleteContext(m_glrc);
481            ::ReleaseDC(m_hwnd, m_hdc);
482        }
483        void destroyBackBufferAndFBO()
484        {
485            if (m_images.getCount())
486            {
487                wglMakeCurrent(m_rendererHDC, m_rendererRC);
488                if (auto rendererRef = m_renderer->get())
489                {
490                    rendererRef->glDeleteFramebuffers(1, &m_framebuffer);
491                }
492                wglMakeCurrent(m_hdc, m_glrc);
493                glDeleteTextures(1, &m_backBuffer);
494                for (auto image : m_images)
495                    image->m_handle = 0;
496                m_images.clear();
497            }
498        }
499        void createBackBufferAndFBO()
500        {
501            if (m_desc.width > 0 && m_desc.height > 0)
502            {
503                wglMakeCurrent(m_rendererHDC, m_rendererRC);
504
505                glGenTextures(1, &m_backBuffer);
506                glBindTexture(GL_TEXTURE_2D, m_backBuffer);
507                glTexImage2D(
508                    GL_TEXTURE_2D,
509                    0,
510                    GL_RGBA8,
511                    m_desc.width,
512                    m_desc.height,
513                    0,
514                    GL_RGBA,
515                    GL_UNSIGNED_BYTE,
516                    nullptr);
517
518                wglMakeCurrent(m_hdc, m_glrc);
519                m_renderer->get()->glGenFramebuffers(1, &m_framebuffer);
520                m_renderer->get()->glBindFramebuffer(GL_READ_FRAMEBUFFER, m_framebuffer);
521                m_renderer->get()->glFramebufferTexture2D(
522                    GL_READ_FRAMEBUFFER,
523                    GL_COLOR_ATTACHMENT0,
524                    GL_TEXTURE_2D,
525                    m_backBuffer,
526                    0);
527
528                m_images.clear();
529                for (GfxIndex i = 0; i < m_desc.imageCount; i++)
530                {
531                    ITextureResource::Desc imageDesc = {};
532                    imageDesc.allowedStates = ResourceStateSet(
533                        ResourceState::Present,
534                        ResourceState::RenderTarget,
535                        ResourceState::CopyDestination);
536                    imageDesc.type = IResource::Type::Texture2D;
537                    imageDesc.arraySize = 0;
538                    imageDesc.format = m_desc.format;
539                    imageDesc.size.width = m_desc.width;
540                    imageDesc.size.height = m_desc.height;
541                    imageDesc.size.depth = 1;
542                    imageDesc.numMipLevels = 1;
543                    imageDesc.defaultState = ResourceState::Present;
544                    RefPtr<TextureResourceImpl> tex =
545                        new TextureResourceImpl(imageDesc, m_renderer);
546                    tex->m_handle = m_backBuffer;
547                    m_images.add(tex);
548                }
549                wglMakeCurrent(m_rendererHDC, m_rendererRC);
550            }
551        }
552        Result init(GLDevice* renderer, const ISwapchain::Desc& desc, WindowHandle window)
553        {
554            m_renderer = renderer->m_weakRenderer.Ptr();
555            m_rendererHDC = renderer->m_hdc;
556            m_rendererRC = renderer->m_glContext;
557
558            m_hwnd = (HWND)window.handleValues[0];
559            m_hdc = ::GetDC(m_hwnd);
560            m_glrc = renderer->createGLContext(m_hdc);
561            m_desc = desc;
562
563            createBackBufferAndFBO();
564            return SLANG_OK;
565        }
566        virtual SLANG_NO_THROW const Desc& SLANG_MCALL getDesc() override { return m_desc; }
567        virtual SLANG_NO_THROW Result SLANG_MCALL
568        getImage(GfxIndex index, ITextureResource** outResource) override
569        {
570            returnComPtr(outResource, m_images[index]);
571            return SLANG_OK;
572        }
573        virtual SLANG_NO_THROW Result SLANG_MCALL present() override
574        {
575            glFlush();
576            wglMakeCurrent(m_hdc, m_glrc);
577            auto renderer = m_renderer->get();
578            renderer->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
579            renderer->glBindFramebuffer(GL_READ_FRAMEBUFFER, m_framebuffer);
580            renderer->glBlitFramebuffer(
581                0,
582                0,
583                m_desc.width,
584                m_desc.height,
585                0,
586                0,
587                m_desc.width,
588                m_desc.height,
589                GL_COLOR_BUFFER_BIT,
590                GL_NEAREST);
591            SwapBuffers(m_hdc);
592            wglMakeCurrent(renderer->m_hdc, renderer->m_glContext);
593            return SLANG_OK;
594        }
595
596        virtual SLANG_NO_THROW int SLANG_MCALL acquireNextImage() override
597        {
598            if (m_desc.width > 0 && m_desc.height > 0)
599                return 0;
600            return -1;
601        }
602
603        virtual SLANG_NO_THROW Result SLANG_MCALL resize(GfxCount width, GfxCount height) override
604        {
605            if (width > 0 && height > 0 && (width != m_desc.width || height != m_desc.height))
606            {
607                m_desc.width = width;
608                m_desc.height = height;
609                destroyBackBufferAndFBO();
610                createBackBufferAndFBO();
611            }
612            return SLANG_OK;
613        }
614
615        virtual SLANG_NO_THROW bool SLANG_MCALL isOccluded() override { return false; }
616        virtual SLANG_NO_THROW Result SLANG_MCALL setFullScreenMode(bool mode) override
617        {
618            return SLANG_FAIL;
619        }
620
621    public:
622        RefPtr<WeakSink<GLDevice>> m_renderer = nullptr;
623        GLuint m_framebuffer;
624        GLuint m_backBuffer;
625        HGLRC m_glrc;
626        HWND m_hwnd;
627        HDC m_hdc;
628
629        HDC m_rendererHDC;
630        HGLRC m_rendererRC;
631        ISwapchain::Desc m_desc;
632        ShortList<RefPtr<TextureResourceImpl>> m_images;
633    };
634
635    class ShaderProgramImpl : public ShaderProgramBase
636    {
637    public:
638        ShaderProgramImpl(WeakSink<GLDevice>* renderer, GLuint id)
639            : m_renderer(renderer), m_id(id)
640        {
641        }
642        ~ShaderProgramImpl()
643        {
644            if (auto renderer = m_renderer->get())
645            {
646                renderer->glDeleteProgram(m_id);
647            }
648        }
649
650        GLuint m_id;
651        RefPtr<WeakSink<GLDevice>> m_renderer;
652    };
653
654    class PipelineStateImpl : public PipelineStateBase
655    {
656    public:
657        RefPtr<InputLayoutImpl> m_inputLayout;
658        void init(const GraphicsPipelineStateDesc& inDesc)
659        {
660            PipelineStateDesc pipelineDesc;
661            pipelineDesc.type = PipelineType::Graphics;
662            pipelineDesc.graphics = inDesc;
663            initializeBase(pipelineDesc);
664        }
665        void init(const ComputePipelineStateDesc& inDesc)
666        {
667            PipelineStateDesc pipelineDesc;
668            pipelineDesc.type = PipelineType::Compute;
669            pipelineDesc.compute = inDesc;
670            initializeBase(pipelineDesc);
671        }
672    };
673
674    struct RootBindingState
675    {
676        List<RefPtr<TextureViewImpl>> textureBindings;
677        List<RefPtr<TextureViewImpl>> imageBindings;
678        List<GLuint> samplerBindings;
679        List<GLuint> uniformBufferBindings;
680        List<GLuint> storageBufferBindings;
681    };
682
683    class ShaderObjectLayoutImpl : public ShaderObjectLayoutBase
684    {
685    public:
686        struct BindingRangeInfo
687        {
688            slang::BindingType bindingType;
689            Index count;
690            Index baseIndex;
691            Index subObjectIndex;
692            bool isSpecializable;
693        };
694
695        struct SubObjectRangeInfo
696        {
697            RefPtr<ShaderObjectLayoutImpl> layout;
698            Index bindingRangeIndex;
699        };
700
701        struct Builder
702        {
703        public:
704            Builder(RendererBase* renderer, slang::ISession* session)
705                : m_renderer(renderer), m_session(session)
706            {
707            }
708
709            RendererBase* m_renderer;
710            slang::ISession* m_session;
711            slang::TypeLayoutReflection* m_elementTypeLayout;
712
713            /// The container type of this shader object. When `m_containerType` is
714            /// `StructuredBuffer` or `UnsizedArray`, this shader object represents a collection
715            /// instead of a single object.
716            ShaderObjectContainerType m_containerType = ShaderObjectContainerType::None;
717
718            List<BindingRangeInfo> m_bindingRanges;
719            List<SubObjectRangeInfo> m_subObjectRanges;
720
721            Index m_textureCount = 0;
722            Index m_imageCount = 0;
723            Index m_storageBufferCount = 0;
724            Index m_subObjectCount = 0;
725
726            Result setElementTypeLayout(slang::TypeLayoutReflection* typeLayout)
727            {
728                typeLayout = _unwrapParameterGroups(typeLayout, m_containerType);
729
730                m_elementTypeLayout = typeLayout;
731
732                // Compute the binding ranges that are used to store
733                // the logical contents of the object in memory.
734
735                SlangInt bindingRangeCount = typeLayout->getBindingRangeCount();
736                for (SlangInt r = 0; r < bindingRangeCount; ++r)
737                {
738                    slang::BindingType slangBindingType = typeLayout->getBindingRangeType(r);
739                    SlangInt count = typeLayout->getBindingRangeBindingCount(r);
740                    slang::TypeLayoutReflection* slangLeafTypeLayout =
741                        typeLayout->getBindingRangeLeafTypeLayout(r);
742
743                    BindingRangeInfo bindingRangeInfo;
744                    bindingRangeInfo.bindingType = slangBindingType;
745                    bindingRangeInfo.count = count;
746                    bindingRangeInfo.isSpecializable = typeLayout->isBindingRangeSpecializable(r);
747                    switch (slangBindingType)
748                    {
749                    case slang::BindingType::ConstantBuffer:
750                    case slang::BindingType::ParameterBlock:
751                    case slang::BindingType::ExistentialValue:
752                        bindingRangeInfo.baseIndex = m_subObjectCount;
753                        bindingRangeInfo.subObjectIndex = m_subObjectCount;
754                        m_subObjectCount += count;
755                        break;
756                    case slang::BindingType::RawBuffer:
757                    case slang::BindingType::MutableRawBuffer:
758                        if (slangLeafTypeLayout->getType()->getElementType() != nullptr)
759                        {
760                            // A structured buffer occupies both a resource slot and
761                            // a sub-object slot.
762                            bindingRangeInfo.subObjectIndex = m_subObjectCount;
763                            m_subObjectCount += count;
764                        }
765                        bindingRangeInfo.baseIndex = m_storageBufferCount;
766                        m_storageBufferCount += count;
767                        break;
768                    case slang::BindingType::Sampler:
769                        break;
770
771                    case slang::BindingType::Texture:
772                    case slang::BindingType::CombinedTextureSampler:
773                        bindingRangeInfo.baseIndex = m_textureCount;
774                        m_textureCount += count;
775                        break;
776
777                    case slang::BindingType::MutableTexture:
778                        bindingRangeInfo.baseIndex = m_imageCount;
779                        m_imageCount += count;
780                        break;
781
782                    case slang::BindingType::MutableTypedBuffer:
783                        bindingRangeInfo.baseIndex = m_storageBufferCount;
784                        m_storageBufferCount += count;
785                        break;
786                    case slang::BindingType::VaryingInput:
787                    case slang::BindingType::VaryingOutput:
788                        break;
789                    default:
790                        SLANG_ASSERT(!"unsupported binding type.");
791                        break;
792                    }
793                    m_bindingRanges.add(bindingRangeInfo);
794                }
795
796                SlangInt subObjectRangeCount = typeLayout->getSubObjectRangeCount();
797                for (SlangInt r = 0; r < subObjectRangeCount; ++r)
798                {
799                    SlangInt bindingRangeIndex = typeLayout->getSubObjectRangeBindingRangeIndex(r);
800                    auto slangBindingType = typeLayout->getBindingRangeType(bindingRangeIndex);
801                    slang::TypeLayoutReflection* slangLeafTypeLayout =
802                        typeLayout->getBindingRangeLeafTypeLayout(bindingRangeIndex);
803
804                    // A sub-object range can either represent a sub-object of a known
805                    // type, like a `ConstantBuffer<Foo>` or `ParameterBlock<Foo>`
806                    // (in which case we can pre-compute a layout to use, based on
807                    // the type `Foo`) *or* it can represent a sub-object of some
808                    // existential type (e.g., `IBar`) in which case we cannot
809                    // know the appropraite type/layout of sub-object to allocate.
810                    //
811                    RefPtr<ShaderObjectLayoutImpl> subObjectLayout;
812                    if (slangBindingType != slang::BindingType::ExistentialValue)
813                    {
814                        createForElementType(
815                            m_renderer,
816                            m_session,
817                            slangLeafTypeLayout->getElementTypeLayout(),
818                            subObjectLayout.writeRef());
819                    }
820
821                    SubObjectRangeInfo subObjectRange;
822                    subObjectRange.bindingRangeIndex = bindingRangeIndex;
823                    subObjectRange.layout = subObjectLayout;
824
825                    m_subObjectRanges.add(subObjectRange);
826                }
827                return SLANG_OK;
828            }
829
830            SlangResult build(ShaderObjectLayoutImpl** outLayout)
831            {
832                auto layout = RefPtr<ShaderObjectLayoutImpl>(new ShaderObjectLayoutImpl());
833                SLANG_RETURN_ON_FAIL(layout->_init(this));
834
835                returnRefPtrMove(outLayout, layout);
836                return SLANG_OK;
837            }
838        };
839
840        static Result createForElementType(
841            RendererBase* renderer,
842            slang::ISession* session,
843            slang::TypeLayoutReflection* elementType,
844            ShaderObjectLayoutImpl** outLayout)
845        {
846            Builder builder(renderer, session);
847            builder.setElementTypeLayout(elementType);
848            return builder.build(outLayout);
849        }
850
851        List<BindingRangeInfo> const& getBindingRanges() { return m_bindingRanges; }
852
853        Index getBindingRangeCount() { return m_bindingRanges.getCount(); }
854
855        BindingRangeInfo const& getBindingRange(Index index) { return m_bindingRanges[index]; }
856
857        Index getTextureCount() { return m_textureCount; }
858        Index getImageCount() { return m_imageCount; }
859        Index getStorageBufferCount() { return m_storageBufferCount; }
860        Index getSubObjectCount() { return m_subObjectCount; }
861
862        SubObjectRangeInfo const& getSubObjectRange(Index index)
863        {
864            return m_subObjectRanges[index];
865        }
866        List<SubObjectRangeInfo> const& getSubObjectRanges() { return m_subObjectRanges; }
867
868        RendererBase* getRenderer() { return m_renderer; }
869
870        slang::TypeReflection* getType() { return m_elementTypeLayout->getType(); }
871
872    protected:
873        Result _init(Builder const* builder)
874        {
875            auto renderer = builder->m_renderer;
876
877            initBase(renderer, builder->m_session, builder->m_elementTypeLayout);
878
879            m_bindingRanges = builder->m_bindingRanges;
880
881            m_textureCount = builder->m_textureCount;
882            m_imageCount = builder->m_imageCount;
883            m_storageBufferCount = builder->m_storageBufferCount;
884            m_subObjectCount = builder->m_subObjectCount;
885            m_subObjectRanges = builder->m_subObjectRanges;
886
887            m_containerType = builder->m_containerType;
888            return SLANG_OK;
889        }
890
891        List<BindingRangeInfo> m_bindingRanges;
892        Index m_textureCount = 0;
893        Index m_imageCount = 0;
894        Index m_storageBufferCount = 0;
895        Index m_subObjectCount = 0;
896        List<SubObjectRangeInfo> m_subObjectRanges;
897    };
898
899    class RootShaderObjectLayoutImpl : public ShaderObjectLayoutImpl
900    {
901        typedef ShaderObjectLayoutImpl Super;
902
903    public:
904        struct EntryPointInfo
905        {
906            RefPtr<ShaderObjectLayoutImpl> layout;
907        };
908
909        struct Builder : Super::Builder
910        {
911            Builder(
912                RendererBase* renderer,
913                slang::IComponentType* program,
914                slang::ProgramLayout* programLayout)
915                : Super::Builder(renderer, program->getSession())
916                , m_program(program)
917                , m_programLayout(programLayout)
918            {
919            }
920
921            Result build(RootShaderObjectLayoutImpl** outLayout)
922            {
923                RefPtr<RootShaderObjectLayoutImpl> layout = new RootShaderObjectLayoutImpl();
924                SLANG_RETURN_ON_FAIL(layout->_init(this));
925
926                returnRefPtrMove(outLayout, layout);
927                return SLANG_OK;
928            }
929
930            void addGlobalParams(slang::VariableLayoutReflection* globalsLayout)
931            {
932                setElementTypeLayout(globalsLayout->getTypeLayout());
933            }
934
935            void addEntryPoint(SlangStage stage, ShaderObjectLayoutImpl* entryPointLayout)
936            {
937                EntryPointInfo info;
938                info.layout = entryPointLayout;
939                m_entryPoints.add(info);
940            }
941
942            slang::IComponentType* m_program;
943            slang::ProgramLayout* m_programLayout;
944            List<EntryPointInfo> m_entryPoints;
945        };
946
947        EntryPointInfo& getEntryPoint(Index index) { return m_entryPoints[index]; }
948
949        List<EntryPointInfo>& getEntryPoints() { return m_entryPoints; }
950
951        static Result create(
952            RendererBase* renderer,
953            slang::IComponentType* program,
954            slang::ProgramLayout* programLayout,
955            RootShaderObjectLayoutImpl** outLayout)
956        {
957            RootShaderObjectLayoutImpl::Builder builder(renderer, program, programLayout);
958            builder.addGlobalParams(programLayout->getGlobalParamsVarLayout());
959
960            SlangInt entryPointCount = programLayout->getEntryPointCount();
961            for (SlangInt e = 0; e < entryPointCount; ++e)
962            {
963                auto slangEntryPoint = programLayout->getEntryPointByIndex(e);
964                RefPtr<ShaderObjectLayoutImpl> entryPointLayout;
965                SLANG_RETURN_ON_FAIL(ShaderObjectLayoutImpl::createForElementType(
966                    renderer,
967                    program->getSession(),
968                    slangEntryPoint->getTypeLayout(),
969                    entryPointLayout.writeRef()));
970                builder.addEntryPoint(slangEntryPoint->getStage(), entryPointLayout);
971            }
972
973            SLANG_RETURN_ON_FAIL(builder.build(outLayout));
974
975            return SLANG_OK;
976        }
977
978        slang::IComponentType* getSlangProgram() const { return m_program; }
979        slang::ProgramLayout* getSlangProgramLayout() const { return m_programLayout; }
980
981    protected:
982        Result _init(Builder const* builder)
983        {
984            auto renderer = builder->m_renderer;
985
986            SLANG_RETURN_ON_FAIL(Super::_init(builder));
987
988            m_program = builder->m_program;
989            m_programLayout = builder->m_programLayout;
990            m_entryPoints = builder->m_entryPoints;
991            return SLANG_OK;
992        }
993
994        ComPtr<slang::IComponentType> m_program;
995        slang::ProgramLayout* m_programLayout = nullptr;
996
997        List<EntryPointInfo> m_entryPoints;
998    };
999
1000    class ShaderObjectImpl : public ShaderObjectBaseImpl<
1001                                 ShaderObjectImpl,
1002                                 ShaderObjectLayoutImpl,
1003                                 SimpleShaderObjectData>
1004    {
1005    public:
1006        static Result create(
1007            IDevice* device,
1008            ShaderObjectLayoutImpl* layout,
1009            ShaderObjectImpl** outShaderObject)
1010        {
1011            auto object = RefPtr<ShaderObjectImpl>(new ShaderObjectImpl());
1012            SLANG_RETURN_ON_FAIL(object->init(device, layout));
1013
1014            returnRefPtrMove(outShaderObject, object);
1015            return SLANG_OK;
1016        }
1017
1018        RendererBase* getDevice() { return m_layout->getDevice(); }
1019
1020        SLANG_NO_THROW GfxCount SLANG_MCALL getEntryPointCount() SLANG_OVERRIDE { return 0; }
1021
1022        SLANG_NO_THROW Result SLANG_MCALL
1023        getEntryPoint(GfxIndex index, IShaderObject** outEntryPoint) SLANG_OVERRIDE
1024        {
1025            *outEntryPoint = nullptr;
1026            return SLANG_OK;
1027        }
1028
1029        ShaderObjectLayoutImpl* getLayout()
1030        {
1031            return static_cast<ShaderObjectLayoutImpl*>(m_layout.Ptr());
1032        }
1033
1034        virtual SLANG_NO_THROW const void* SLANG_MCALL getRawData() override
1035        {
1036            return m_data.getBuffer();
1037        }
1038
1039        virtual SLANG_NO_THROW size_t SLANG_MCALL getSize() override
1040        {
1041            return (size_t)m_data.getCount();
1042        }
1043
1044        SLANG_NO_THROW Result SLANG_MCALL
1045        setData(ShaderOffset const& inOffset, void const* data, size_t inSize) SLANG_OVERRIDE
1046        {
1047            Index offset = inOffset.uniformOffset;
1048            Index size = inSize;
1049
1050            char* dest = m_data.getBuffer();
1051            Index availableSize = m_data.getCount();
1052
1053            // TODO: We really should bounds-check access rather than silently ignoring sets
1054            // that are too large, but we have several test cases that set more data than
1055            // an object actually stores on several targets...
1056            //
1057            if (offset < 0)
1058            {
1059                size += offset;
1060                offset = 0;
1061            }
1062            if ((offset + size) >= availableSize)
1063            {
1064                size = availableSize - offset;
1065            }
1066
1067            memcpy(dest + offset, data, size);
1068
1069            return SLANG_OK;
1070        }
1071
1072
1073        SLANG_NO_THROW Result SLANG_MCALL
1074        setResource(ShaderOffset const& offset, IResourceView* resourceView) SLANG_OVERRIDE
1075        {
1076            if (offset.bindingRangeIndex < 0)
1077                return SLANG_E_INVALID_ARG;
1078            auto layout = getLayout();
1079            if (offset.bindingRangeIndex >= layout->getBindingRangeCount())
1080                return SLANG_E_INVALID_ARG;
1081            auto& bindingRange = layout->getBindingRange(offset.bindingRangeIndex);
1082
1083            auto resourceViewImpl = static_cast<ResourceViewImpl*>(resourceView);
1084            switch (bindingRange.bindingType)
1085            {
1086            case slang::BindingType::MutableRawBuffer:
1087            case slang::BindingType::MutableTypedBuffer:
1088            case slang::BindingType::RawBuffer:
1089            case slang::BindingType::TypedBuffer:
1090                m_storageBuffers[bindingRange.baseIndex + offset.bindingArrayIndex] =
1091                    static_cast<BufferViewImpl*>(resourceView);
1092                break;
1093            case slang::BindingType::MutableTexture:
1094                m_images[bindingRange.baseIndex + offset.bindingArrayIndex] =
1095                    static_cast<TextureViewImpl*>(resourceView);
1096                break;
1097            case slang::BindingType::Texture:
1098                m_textures[bindingRange.baseIndex + offset.bindingArrayIndex] =
1099                    static_cast<TextureViewImpl*>(resourceView);
1100                m_samplers[bindingRange.baseIndex + offset.bindingArrayIndex] = nullptr;
1101                break;
1102            }
1103            return SLANG_OK;
1104        }
1105
1106        SLANG_NO_THROW Result SLANG_MCALL
1107        setSampler(ShaderOffset const& offset, ISamplerState* sampler) SLANG_OVERRIDE
1108        {
1109            if (offset.bindingRangeIndex < 0)
1110                return SLANG_E_INVALID_ARG;
1111            auto layout = getLayout();
1112            if (offset.bindingRangeIndex >= layout->getBindingRangeCount())
1113                return SLANG_E_INVALID_ARG;
1114            auto& bindingRange = layout->getBindingRange(offset.bindingRangeIndex);
1115
1116            m_samplers[bindingRange.baseIndex + offset.bindingArrayIndex] =
1117                static_cast<SamplerStateImpl*>(sampler);
1118            return SLANG_OK;
1119        }
1120
1121        SLANG_NO_THROW Result SLANG_MCALL setCombinedTextureSampler(
1122            ShaderOffset const& offset,
1123            IResourceView* textureView,
1124            ISamplerState* sampler) SLANG_OVERRIDE
1125        {
1126            if (offset.bindingRangeIndex < 0)
1127                return SLANG_E_INVALID_ARG;
1128            auto layout = getLayout();
1129            if (offset.bindingRangeIndex >= layout->getBindingRangeCount())
1130                return SLANG_E_INVALID_ARG;
1131            auto& bindingRange = layout->getBindingRange(offset.bindingRangeIndex);
1132            m_textures[bindingRange.baseIndex + offset.bindingArrayIndex] =
1133                static_cast<TextureViewImpl*>(textureView);
1134            m_samplers[bindingRange.baseIndex + offset.bindingArrayIndex] =
1135                static_cast<SamplerStateImpl*>(sampler);
1136            return SLANG_OK;
1137        }
1138
1139    public:
1140    protected:
1141        friend class ProgramVars;
1142
1143        Result init(IDevice* device, ShaderObjectLayoutImpl* layout)
1144        {
1145            m_layout = layout;
1146
1147            // If the layout tells us that there is any uniform data,
1148            // then we will allocate a CPU memory buffer to hold that data
1149            // while it is being set from the host.
1150            //
1151            // Once the user is done setting the parameters/fields of this
1152            // shader object, we will produce a GPU-memory version of the
1153            // uniform data (which includes values from this object and
1154            // any existential-type sub-objects).
1155            //
1156            size_t uniformSize = layout->getElementTypeLayout()->getSize();
1157            if (uniformSize)
1158            {
1159                m_data.setCount(uniformSize);
1160                memset(m_data.getBuffer(), 0, uniformSize);
1161            }
1162
1163            m_samplers.setCount(layout->getTextureCount());
1164            m_textures.setCount(layout->getTextureCount());
1165            m_images.setCount(layout->getImageCount());
1166            m_storageBuffers.setCount(layout->getStorageBufferCount());
1167
1168            // If the layout specifies that we have any sub-objects, then
1169            // we need to size the array to account for them.
1170            //
1171            Index subObjectCount = layout->getSubObjectCount();
1172            m_objects.setCount(subObjectCount);
1173
1174            for (auto subObjectRangeInfo : layout->getSubObjectRanges())
1175            {
1176                auto subObjectLayout = subObjectRangeInfo.layout;
1177
1178                // In the case where the sub-object range represents an
1179                // existential-type leaf field (e.g., an `IBar`), we
1180                // cannot pre-allocate the object(s) to go into that
1181                // range, since we can't possibly know what to allocate
1182                // at this point.
1183                //
1184                if (!subObjectLayout)
1185                    continue;
1186                //
1187                // Otherwise, we will allocate a sub-object to fill
1188                // in each entry in this range, based on the layout
1189                // information we already have.
1190
1191                auto& bindingRangeInfo =
1192                    layout->getBindingRange(subObjectRangeInfo.bindingRangeIndex);
1193                for (Index i = 0; i < bindingRangeInfo.count; ++i)
1194                {
1195                    RefPtr<ShaderObjectImpl> subObject;
1196                    SLANG_RETURN_ON_FAIL(
1197                        ShaderObjectImpl::create(device, subObjectLayout, subObject.writeRef()));
1198                    m_objects[bindingRangeInfo.subObjectIndex + i] = subObject;
1199                }
1200            }
1201
1202            return SLANG_OK;
1203        }
1204
1205        /// Write the uniform/ordinary data of this object into the given `dest` buffer at the given
1206        /// `offset`
1207        Result _writeOrdinaryData(
1208            GLDevice* device,
1209            BufferResourceImpl* buffer,
1210            size_t offset,
1211            size_t destSize,
1212            ShaderObjectLayoutImpl* specializedLayout)
1213        {
1214            auto src = m_data.getBuffer();
1215            auto srcSize = size_t(m_data.getCount());
1216
1217            SLANG_ASSERT(srcSize <= destSize);
1218
1219            device->uploadBufferData(buffer, offset, srcSize, src);
1220
1221            // In the case where this object has any sub-objects of
1222            // existential/interface type, we need to recurse on those objects
1223            // that need to write their state into an appropriate "pending" allocation.
1224            //
1225            // Note: Any values that could fit into the "payload" included
1226            // in the existential-type field itself will have already been
1227            // written as part of `setObject()`. This loop only needs to handle
1228            // those sub-objects that do not "fit."
1229            //
1230            // An implementers looking at this code might wonder if things could be changed
1231            // so that *all* writes related to sub-objects for interface-type fields could
1232            // be handled in this one location, rather than having some in `setObject()` and
1233            // others handled here.
1234            //
1235            Index subObjectRangeCounter = 0;
1236            for (auto const& subObjectRangeInfo : specializedLayout->getSubObjectRanges())
1237            {
1238                Index subObjectRangeIndex = subObjectRangeCounter++;
1239                auto const& bindingRangeInfo =
1240                    specializedLayout->getBindingRange(subObjectRangeInfo.bindingRangeIndex);
1241
1242                // We only need to handle sub-object ranges for interface/existential-type fields,
1243                // because fields of constant-buffer or parameter-block type are responsible for
1244                // the ordinary/uniform data of their own existential/interface-type sub-objects.
1245                //
1246                if (bindingRangeInfo.bindingType != slang::BindingType::ExistentialValue)
1247                    continue;
1248
1249                // Each sub-object range represents a single "leaf" field, but might be nested
1250                // under zero or more outer arrays, such that the number of existential values
1251                // in the same range can be one or more.
1252                //
1253                auto count = bindingRangeInfo.count;
1254
1255                // We are not concerned with the case where the existential value(s) in the range
1256                // git into the payload part of the leaf field.
1257                //
1258                // In the case where the value didn't fit, the Slang layout strategy would have
1259                // considered the requirements of the value as a "pending" allocation, and would
1260                // allocate storage for the ordinary/uniform part of that pending allocation inside
1261                // of the parent object's type layout.
1262                //
1263                // Here we assume that the Slang reflection API can provide us with a single byte
1264                // offset and stride for the location of the pending data allocation in the
1265                // specialized type layout, which will store the values for this sub-object range.
1266                //
1267                // TODO: The reflection API functions we are assuming here haven't been implemented
1268                // yet, so the functions being called here are stubs.
1269                //
1270                // TODO: It might not be that a single sub-object range can reliably map to a single
1271                // contiguous array with a single stride; we need to carefully consider what the
1272                // layout logic does for complex cases with multiple layers of nested arrays and
1273                // structures.
1274                //
1275                size_t subObjectRangePendingDataOffset =
1276                    0; // subObjectRangeInfo.offset.pendingOrdinaryData;
1277                size_t subObjectRangePendingDataStride =
1278                    0; // subObjectRangeInfo.stride.pendingOrdinaryData;
1279
1280                // If the range doesn't actually need/use the "pending" allocation at all, then
1281                // we need to detect that case and skip such ranges.
1282                //
1283                // TODO: This should probably be handled on a per-object basis by caching a "does it
1284                // fit?" bit as part of the information for bound sub-objects, given that we already
1285                // compute the "does it fit?" status as part of `setObject()`.
1286                //
1287                if (subObjectRangePendingDataOffset == 0)
1288                    continue;
1289
1290                for (Slang::Index i = 0; i < count; ++i)
1291                {
1292                    auto subObject = m_objects[bindingRangeInfo.subObjectIndex + i];
1293
1294                    RefPtr<ShaderObjectLayoutImpl> subObjectLayout;
1295                    SLANG_RETURN_ON_FAIL(
1296                        subObject->_getSpecializedLayout(subObjectLayout.writeRef()));
1297
1298                    auto subObjectOffset =
1299                        subObjectRangePendingDataOffset + i * subObjectRangePendingDataStride;
1300
1301                    subObject->_writeOrdinaryData(
1302                        device,
1303                        buffer,
1304                        offset + subObjectOffset,
1305                        destSize - subObjectOffset,
1306                        subObjectLayout);
1307                }
1308            }
1309
1310            return SLANG_OK;
1311        }
1312
1313        /// Ensure that the `m_ordinaryDataBuffer` has been created, if it is needed
1314        Result _ensureOrdinaryDataBufferCreatedIfNeeded(GLDevice* device)
1315        {
1316            // If we have already created a buffer to hold ordinary data, then we should
1317            // simply re-use that buffer rather than re-create it.
1318            //
1319            // TODO: Simply re-using the buffer without any kind of validation checks
1320            // means that we are assuming that users cannot or will not perform any `set`
1321            // operations on a shader object once an operation has requested this buffer
1322            // be created. We need to enforce that rule if we want to rely on it.
1323            //
1324            if (m_ordinaryDataBuffer)
1325                return SLANG_OK;
1326
1327            // Computing the size of the ordinary data buffer is *not* just as simple
1328            // as using the size of the `m_ordinayData` array that we store. The reason
1329            // for the added complexity is that interface-type fields may lead to the
1330            // storage being specialized such that it needs extra appended data to
1331            // store the concrete values that logically belong in those interface-type
1332            // fields but wouldn't fit in the fixed-size allocation we gave them.
1333            //
1334            // TODO: We need to actually implement that logic by using reflection
1335            // data computed for the specialized type of this shader object.
1336            // For now we just make the simple assumption described above despite
1337            // knowing that it is false.
1338            //
1339            RefPtr<ShaderObjectLayoutImpl> specializedLayout;
1340            SLANG_RETURN_ON_FAIL(_getSpecializedLayout(specializedLayout.writeRef()));
1341
1342            auto specializedOrdinaryDataSize = specializedLayout->getElementTypeLayout()->getSize();
1343            if (specializedOrdinaryDataSize == 0)
1344                return SLANG_OK;
1345
1346            // Once we have computed how large the buffer should be, we can allocate
1347            // it using the existing public `IDevice` API.
1348            //
1349
1350            ComPtr<IBufferResource> bufferResourcePtr;
1351            IBufferResource::Desc bufferDesc;
1352            bufferDesc.type = IResource::Type::Buffer;
1353            bufferDesc.sizeInBytes = specializedOrdinaryDataSize;
1354            bufferDesc.defaultState = ResourceState::ConstantBuffer;
1355            bufferDesc.allowedStates =
1356                ResourceStateSet(ResourceState::ConstantBuffer, ResourceState::CopyDestination);
1357            bufferDesc.memoryType = MemoryType::Upload;
1358            SLANG_RETURN_ON_FAIL(
1359                device->createBufferResource(bufferDesc, nullptr, bufferResourcePtr.writeRef()));
1360            m_ordinaryDataBuffer = static_cast<BufferResourceImpl*>(bufferResourcePtr.get());
1361
1362            // Once the buffer is allocated, we can use `_writeOrdinaryData` to fill it in.
1363            //
1364            // Note that `_writeOrdinaryData` is potentially recursive in the case
1365            // where this object contains interface/existential-type fields, so we
1366            // don't need or want to inline it into this call site.
1367            //
1368            SLANG_RETURN_ON_FAIL(_writeOrdinaryData(
1369                device,
1370                m_ordinaryDataBuffer,
1371                0,
1372                specializedOrdinaryDataSize,
1373                specializedLayout));
1374
1375            return SLANG_OK;
1376        }
1377
1378        /// Bind the buffer for ordinary/uniform data, if needed
1379        Result _bindOrdinaryDataBufferIfNeeded(GLDevice* device, RootBindingState* bindingState)
1380        {
1381            // We start by ensuring that the buffer is created, if it is needed.
1382            //
1383            SLANG_RETURN_ON_FAIL(_ensureOrdinaryDataBufferCreatedIfNeeded(device));
1384
1385            // If we did indeed need/create a buffer, then we must bind it
1386            // into root binding state.
1387            //
1388            if (m_ordinaryDataBuffer)
1389            {
1390                bindingState->uniformBufferBindings.add(m_ordinaryDataBuffer->m_handle);
1391            }
1392
1393            return SLANG_OK;
1394        }
1395
1396    public:
1397        virtual Result bindObject(GLDevice* device, RootBindingState* bindingState)
1398        {
1399            ShaderObjectLayoutImpl* layout = getLayout();
1400
1401            Index baseRangeIndex = 0;
1402            SLANG_RETURN_ON_FAIL(_bindOrdinaryDataBufferIfNeeded(device, bindingState));
1403
1404            for (auto sampler : m_samplers)
1405                bindingState->samplerBindings.add(sampler ? sampler->m_samplerID : 0);
1406
1407            bindingState->textureBindings.addRange(m_textures);
1408            bindingState->imageBindings.addRange(m_images);
1409
1410            for (auto buffer : m_storageBuffers)
1411                bindingState->storageBufferBindings.add(buffer ? buffer->m_bufferID : 0);
1412
1413            for (auto const& subObjectRange : layout->getSubObjectRanges())
1414            {
1415                auto subObjectLayout = subObjectRange.layout;
1416                auto const& bindingRange =
1417                    layout->getBindingRange(subObjectRange.bindingRangeIndex);
1418
1419                switch (bindingRange.bindingType)
1420                {
1421                case slang::BindingType::ConstantBuffer:
1422                case slang::BindingType::ParameterBlock:
1423                case slang::BindingType::ExistentialValue:
1424                    break;
1425                default:
1426                    continue;
1427                }
1428
1429                for (Index i = 0; i < bindingRange.count; i++)
1430                {
1431                    m_objects[i + bindingRange.subObjectIndex]->bindObject(device, bindingState);
1432                }
1433            }
1434
1435            return SLANG_OK;
1436        }
1437
1438        List<RefPtr<TextureViewImpl>> m_textures;
1439
1440        List<RefPtr<TextureViewImpl>> m_images;
1441
1442        List<RefPtr<SamplerStateImpl>> m_samplers;
1443
1444        List<RefPtr<BufferViewImpl>> m_storageBuffers;
1445
1446        /// A constant buffer used to stored ordinary data for this object
1447        /// and existential-type sub-objects.
1448        ///
1449        /// Created on demand with `_createOrdinaryDataBufferIfNeeded()`
1450        RefPtr<BufferResourceImpl> m_ordinaryDataBuffer;
1451
1452        /// Get the layout of this shader object with specialization arguments considered
1453        ///
1454        /// This operation should only be called after the shader object has been
1455        /// fully filled in and finalized.
1456        ///
1457        Result _getSpecializedLayout(ShaderObjectLayoutImpl** outLayout)
1458        {
1459            if (!m_specializedLayout)
1460            {
1461                SLANG_RETURN_ON_FAIL(_createSpecializedLayout(m_specializedLayout.writeRef()));
1462            }
1463            returnRefPtr(outLayout, m_specializedLayout);
1464            return SLANG_OK;
1465        }
1466
1467        /// Create the layout for this shader object with specialization arguments considered
1468        ///
1469        /// This operation is virtual so that it can be customized by `ProgramVars`.
1470        ///
1471        virtual Result _createSpecializedLayout(ShaderObjectLayoutImpl** outLayout)
1472        {
1473            ExtendedShaderObjectType extendedType;
1474            SLANG_RETURN_ON_FAIL(getSpecializedShaderObjectType(&extendedType));
1475
1476            auto renderer = getRenderer();
1477            RefPtr<ShaderObjectLayoutImpl> layout;
1478            SLANG_RETURN_ON_FAIL(renderer->getShaderObjectLayout(
1479                m_layout->m_slangSession,
1480                extendedType.slangType,
1481                m_layout->getContainerType(),
1482                (ShaderObjectLayoutBase**)layout.writeRef()));
1483
1484            returnRefPtrMove(outLayout, layout);
1485            return SLANG_OK;
1486        }
1487
1488        RefPtr<ShaderObjectLayoutImpl> m_specializedLayout;
1489    };
1490
1491    class MutableShaderObjectImpl
1492        : public MutableShaderObject<MutableShaderObjectImpl, ShaderObjectLayoutImpl>
1493    {
1494    };
1495
1496    class RootShaderObjectImpl : public ShaderObjectImpl
1497    {
1498        typedef ShaderObjectImpl Super;
1499
1500    public:
1501        virtual SLANG_NO_THROW uint32_t SLANG_MCALL addRef() override { return 1; }
1502        virtual SLANG_NO_THROW uint32_t SLANG_MCALL release() override { return 1; }
1503
1504    public:
1505        static Result create(
1506            IDevice* device,
1507            RootShaderObjectLayoutImpl* layout,
1508            RootShaderObjectImpl** outShaderObject)
1509        {
1510            RefPtr<RootShaderObjectImpl> object = new RootShaderObjectImpl();
1511            SLANG_RETURN_ON_FAIL(object->init(device, layout));
1512
1513            returnRefPtrMove(outShaderObject, object);
1514            return SLANG_OK;
1515        }
1516
1517        RootShaderObjectLayoutImpl* getLayout()
1518        {
1519            return static_cast<RootShaderObjectLayoutImpl*>(m_layout.Ptr());
1520        }
1521
1522        SLANG_NO_THROW GfxCount SLANG_MCALL getEntryPointCount() SLANG_OVERRIDE
1523        {
1524            return (GfxCount)m_entryPoints.getCount();
1525        }
1526        SLANG_NO_THROW SlangResult SLANG_MCALL
1527        getEntryPoint(GfxIndex index, IShaderObject** outEntryPoint) SLANG_OVERRIDE
1528        {
1529            *outEntryPoint = m_entryPoints[index];
1530            m_entryPoints[index]->addRef();
1531            return SLANG_OK;
1532        }
1533
1534        virtual Result collectSpecializationArgs(ExtendedShaderObjectTypeList& args) override
1535        {
1536            SLANG_RETURN_ON_FAIL(ShaderObjectImpl::collectSpecializationArgs(args));
1537            for (auto& entryPoint : m_entryPoints)
1538            {
1539                SLANG_RETURN_ON_FAIL(entryPoint->collectSpecializationArgs(args));
1540            }
1541            return SLANG_OK;
1542        }
1543
1544    protected:
1545        virtual Result bindObject(GLDevice* device, RootBindingState* bindingState) override
1546        {
1547            SLANG_RETURN_ON_FAIL(Super::bindObject(device, bindingState));
1548
1549            auto entryPointCount = m_entryPoints.getCount();
1550            for (Index i = 0; i < entryPointCount; ++i)
1551            {
1552                auto entryPoint = m_entryPoints[i];
1553                SLANG_RETURN_ON_FAIL(entryPoint->bindObject(device, bindingState));
1554            }
1555
1556            return SLANG_OK;
1557        }
1558
1559        Result init(IDevice* device, RootShaderObjectLayoutImpl* layout)
1560        {
1561            SLANG_RETURN_ON_FAIL(Super::init(device, layout));
1562
1563            for (auto entryPointInfo : layout->getEntryPoints())
1564            {
1565                RefPtr<ShaderObjectImpl> entryPoint;
1566                SLANG_RETURN_ON_FAIL(
1567                    ShaderObjectImpl::create(device, entryPointInfo.layout, entryPoint.writeRef()));
1568                m_entryPoints.add(entryPoint);
1569            }
1570
1571            return SLANG_OK;
1572        }
1573
1574        Result _createSpecializedLayout(ShaderObjectLayoutImpl** outLayout) SLANG_OVERRIDE
1575        {
1576            ExtendedShaderObjectTypeList specializationArgs;
1577            SLANG_RETURN_ON_FAIL(collectSpecializationArgs(specializationArgs));
1578
1579            // Note: There is an important policy decision being made here that we need
1580            // to approach carefully.
1581            //
1582            // We are doing two different things that affect the layout of a program:
1583            //
1584            // 1. We are *composing* one or more pieces of code (notably the shared global/module
1585            //    stuff and the per-entry-point stuff).
1586            //
1587            // 2. We are *specializing* code that includes generic/existential parameters
1588            //    to concrete types/values.
1589            //
1590            // We need to decide the relative *order* of these two steps, because of how it impacts
1591            // layout. The layout for `specialize(compose(A,B), X, Y)` is potentially different
1592            // form that of `compose(specialize(A,X), speciealize(B,Y))`, even when both are
1593            // semantically equivalent programs.
1594            //
1595            // Right now we are using the first option: we are first generating a full composition
1596            // of all the code we plan to use (global scope plus all entry points), and then
1597            // specializing it to the concatenated specialization argumenst for all of that.
1598            //
1599            // In some cases, though, this model isn't appropriate. For example, when dealing with
1600            // ray-tracing shaders and local root signatures, we really want the parameters of each
1601            // entry point (actually, each entry-point *group*) to be allocated distinct storage,
1602            // which really means we want to compute something like:
1603            //
1604            //      SpecializedGlobals = specialize(compose(ModuleA, ModuleB, ...), X, Y, ...)
1605            //
1606            //      SpecializedEP1 = compose(SpecializedGlobals, specialize(EntryPoint1, T, U, ...))
1607            //      SpecializedEP2 = compose(SpecializedGlobals, specialize(EntryPoint2, A, B, ...))
1608            //
1609            // Note how in this case all entry points agree on the layout for the shared/common
1610            // parmaeters, but their layouts are also independent of one another.
1611            //
1612            // Furthermore, in this example, loading another entry point into the system would not
1613            // rquire re-computing the layouts (or generated kernel code) for any of the entry
1614            // points that had already been loaded (in contrast to a compose-then-specialize
1615            // approach).
1616            //
1617            ComPtr<slang::IComponentType> specializedComponentType;
1618            ComPtr<slang::IBlob> diagnosticBlob;
1619            auto result = getLayout()->getSlangProgram()->specialize(
1620                specializationArgs.components.getArrayView().getBuffer(),
1621                specializationArgs.getCount(),
1622                specializedComponentType.writeRef(),
1623                diagnosticBlob.writeRef());
1624
1625            // TODO: print diagnostic message via debug output interface.
1626
1627            if (result != SLANG_OK)
1628                return result;
1629
1630            auto slangSpecializedLayout = specializedComponentType->getLayout();
1631            RefPtr<RootShaderObjectLayoutImpl> specializedLayout;
1632            RootShaderObjectLayoutImpl::create(
1633                getRenderer(),
1634                specializedComponentType,
1635                slangSpecializedLayout,
1636                specializedLayout.writeRef());
1637
1638            // Note: Computing the layout for the specialized program will have also computed
1639            // the layouts for the entry points, and we really need to attach that information
1640            // to them so that they don't go and try to compute their own specializations.
1641            //
1642            // TODO: Well, if we move to the specialization model described above then maybe
1643            // we *will* want entry points to do their own specialization work...
1644            //
1645            auto entryPointCount = m_entryPoints.getCount();
1646            for (Index i = 0; i < entryPointCount; ++i)
1647            {
1648                auto entryPointInfo = specializedLayout->getEntryPoint(i);
1649                auto entryPointVars = m_entryPoints[i];
1650
1651                entryPointVars->m_specializedLayout = entryPointInfo.layout;
1652            }
1653
1654            returnRefPtrMove(outLayout, specializedLayout);
1655            return SLANG_OK;
1656        }
1657
1658
1659        List<RefPtr<ShaderObjectImpl>> m_entryPoints;
1660    };
1661
1662    enum class GlPixelFormat
1663    {
1664        Unknown,
1665        R8G8B8A8_UNORM,
1666        D32_FLOAT,
1667        D_Unorm24_S8,
1668        D32_FLOAT_S8,
1669        CountOf,
1670    };
1671
1672    struct GlPixelFormatInfo
1673    {
1674        GLint internalFormat; // such as GL_RGBA8
1675        GLenum format;        // such as GL_RGBA
1676        GLenum formatType;    // such as GL_UNSIGNED_BYTE
1677    };
1678
1679    //	void destroyBindingEntries(const BindingState::Desc& desc, const BindingDetail* details);
1680
1681    void bindBufferImpl(
1682        int target,
1683        UInt startSlot,
1684        UInt slotCount,
1685        BufferResource* const* buffers,
1686        const UInt* offsets);
1687    void flushStateForDraw();
1688    GLuint loadShader(GLenum stage, char const* source);
1689    void debugCallback(
1690        GLenum source,
1691        GLenum type,
1692        GLuint id,
1693        GLenum severity,
1694        GLsizei length,
1695        const GLchar* message);
1696
1697    /// Returns GlPixelFormat::Unknown if not an equivalent
1698    static GlPixelFormat _getGlPixelFormat(Format format);
1699
1700    static void APIENTRY staticDebugCallback(
1701        GLenum source,
1702        GLenum type,
1703        GLuint id,
1704        GLenum severity,
1705        GLsizei length,
1706        const GLchar* message,
1707        const void* userParam);
1708    static VertexAttributeFormat getVertexAttributeFormat(Format format);
1709
1710    static void compileTimeAsserts();
1711
1712    // GLDevice members.
1713
1714    DeviceInfo m_info;
1715    String m_adapterName;
1716
1717    HDC m_hdc;
1718    HGLRC m_glContext = 0;
1719    uint32_t m_stencilRef = 0;
1720
1721    GLuint m_vao;
1722    RefPtr<PipelineStateImpl> m_currentPipelineState;
1723    RefPtr<FramebufferImpl> m_currentFramebuffer;
1724    RefPtr<WeakSink<GLDevice>> m_weakRenderer;
1725
1726    RootBindingState m_rootBindingState;
1727
1728    GLenum m_boundPrimitiveTopology = GL_TRIANGLES;
1729    GLuint m_boundVertexStreamBuffers[kMaxVertexStreams];
1730    UInt m_boundVertexStreamOffsets[kMaxVertexStreams];
1731    GLuint m_boundIndexBuffer = 0;
1732    UInt m_boundIndexBufferOffset = 0;
1733    UInt m_boundIndexBufferSize = 0;
1734
1735    Desc m_desc;
1736    WindowHandle m_windowHandle;
1737// Declare a function pointer for each OpenGL
1738// extension function we need to load
1739#define DECLARE_GL_EXTENSION_FUNC(NAME, TYPE) TYPE NAME;
1740    MAP_GL_EXTENSION_FUNCS(DECLARE_GL_EXTENSION_FUNC)
1741    MAP_WGL_EXTENSION_FUNCS(DECLARE_GL_EXTENSION_FUNC)
1742#undef DECLARE_GL_EXTENSION_FUNC
1743
1744    static const GlPixelFormatInfo s_pixelFormatInfos[]; /// Maps GlPixelFormat to a format info
1745};
1746
1747/* static */ GLDevice::GlPixelFormat GLDevice::_getGlPixelFormat(Format format)
1748{
1749    switch (format)
1750    {
1751    case Format::R8G8B8A8_UNORM:
1752        return GlPixelFormat::R8G8B8A8_UNORM;
1753    case Format::D32_FLOAT:
1754        return GlPixelFormat::D32_FLOAT;
1755    // case Format::D24_UNORM_S8_UINT:     return GlPixelFormat::D_Unorm24_S8;
1756    case Format::D32_FLOAT_S8_UINT:
1757        return GlPixelFormat::D32_FLOAT_S8;
1758
1759    default:
1760        return GlPixelFormat::Unknown;
1761    }
1762}
1763
1764/* static */ const GLDevice::GlPixelFormatInfo GLDevice::s_pixelFormatInfos[] = {
1765    // internalType, format, formatType
1766    {0, 0, 0},                                                     // GlPixelFormat::Unknown
1767    {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE},                         // GlPixelFormat::R8G8B8A8_UNORM
1768    {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE}, // GlPixelFormat::D32_FLOAT
1769    {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_BYTE},     // GlPixelFormat::D_Unorm24_S8
1770    {GL_DEPTH32F_STENCIL8,
1771     GL_DEPTH_STENCIL,
1772     GL_FLOAT_32_UNSIGNED_INT_24_8_REV}, // GlPixelFormat::D32_FLOAT_S8
1773
1774};
1775
1776/* static */ void GLDevice::compileTimeAsserts()
1777{
1778    SLANG_COMPILE_TIME_ASSERT(SLANG_COUNT_OF(s_pixelFormatInfos) == int(GlPixelFormat::CountOf));
1779}
1780
1781void GLDevice::debugCallback(
1782    GLenum source,
1783    GLenum type,
1784    GLuint id,
1785    GLenum severity,
1786    GLsizei length,
1787    const GLchar* message)
1788{
1789    DebugMessageType msgType = DebugMessageType::Info;
1790    switch (type)
1791    {
1792    case GL_DEBUG_TYPE_ERROR:
1793        msgType = DebugMessageType::Error;
1794        break;
1795    default:
1796        break;
1797    }
1798    getDebugCallback()->handleMessage(msgType, DebugMessageSource::Driver, message);
1799}
1800
1801/* static */ void APIENTRY GLDevice::staticDebugCallback(
1802    GLenum source,
1803    GLenum type,
1804    GLuint id,
1805    GLenum severity,
1806    GLsizei length,
1807    const GLchar* message,
1808    const void* userParam)
1809{
1810    ((GLDevice*)userParam)->debugCallback(source, type, id, severity, length, message);
1811}
1812
1813/* static */ GLDevice::VertexAttributeFormat GLDevice::getVertexAttributeFormat(Format format)
1814{
1815    switch (format)
1816    {
1817    default:
1818        assert(!"unexpected");
1819        return VertexAttributeFormat();
1820
1821#define CASE(NAME, COUNT, TYPE, NORMALIZED)                           \
1822    case Format::NAME:                                                \
1823        do                                                            \
1824        {                                                             \
1825            VertexAttributeFormat result = {COUNT, TYPE, NORMALIZED}; \
1826            return result;                                            \
1827        } while (0)
1828
1829        CASE(R32G32B32A32_FLOAT, 4, GL_FLOAT, GL_FALSE);
1830        CASE(R32G32B32_FLOAT, 3, GL_FLOAT, GL_FALSE);
1831        CASE(R32G32_FLOAT, 2, GL_FLOAT, GL_FALSE);
1832        CASE(R32_FLOAT, 1, GL_FLOAT, GL_FALSE);
1833#undef CASE
1834    }
1835}
1836
1837void GLDevice::bindBufferImpl(
1838    int target,
1839    UInt startSlot,
1840    UInt slotCount,
1841    BufferResource* const* buffers,
1842    const UInt* offsets)
1843{
1844    for (UInt ii = 0; ii < slotCount; ++ii)
1845    {
1846        UInt slot = startSlot + ii;
1847
1848        BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(buffers[ii]);
1849        GLuint bufferID = buffer ? buffer->m_handle : 0;
1850
1851        assert(!offsets || !offsets[ii]);
1852
1853        glBindBufferBase(target, (GLuint)slot, bufferID);
1854    }
1855}
1856
1857void GLDevice::flushStateForDraw()
1858{
1859    if (m_currentFramebuffer)
1860    {
1861        glBindFramebuffer(GL_FRAMEBUFFER, m_currentFramebuffer->m_framebuffer);
1862        glDrawBuffers(
1863            (GLsizei)m_currentFramebuffer->m_drawBuffers.getCount(),
1864            m_currentFramebuffer->m_drawBuffers.getArrayView().getBuffer());
1865    }
1866    auto inputLayout = m_currentPipelineState->m_inputLayout.Ptr();
1867    auto attrCount = Index(inputLayout->m_attributeCount);
1868    for (Index ii = 0; ii < attrCount; ++ii)
1869    {
1870        auto& attr = inputLayout->m_attributes[ii];
1871
1872        auto streamIndex = attr.streamIndex;
1873
1874        auto stride = inputLayout->m_streams[streamIndex].stride;
1875
1876        glBindBuffer(GL_ARRAY_BUFFER, m_boundVertexStreamBuffers[streamIndex]);
1877
1878        glVertexAttribPointer(
1879            (GLuint)ii,
1880            attr.format.componentCount,
1881            attr.format.componentType,
1882            attr.format.normalized,
1883            (GLsizei)stride,
1884            (GLvoid*)(attr.offset + m_boundVertexStreamOffsets[streamIndex]));
1885
1886        glEnableVertexAttribArray((GLuint)ii);
1887    }
1888    for (Index ii = attrCount; ii < kMaxVertexStreams; ++ii)
1889    {
1890        glDisableVertexAttribArray((GLuint)ii);
1891    }
1892    if (m_boundIndexBuffer)
1893    {
1894        glBindBufferRange(
1895            GL_ELEMENT_ARRAY_BUFFER,
1896            0,
1897            m_boundIndexBuffer,
1898            m_boundIndexBufferOffset,
1899            m_boundIndexBufferSize);
1900    }
1901}
1902
1903GLuint GLDevice::loadShader(GLenum stage, const char* source)
1904{
1905    // GLSL is monumentally stupid. It officially requires the `#version` directive
1906    // to be the first thing in the file, which wouldn't be so bad but the API
1907    // doesn't provide a way to pass a `#define` into your shader other than by
1908    // prepending it to the whole thing.
1909    //
1910    // We are going to solve this problem by doing some surgery on the source
1911    // that was passed in.
1912
1913    const char* sourceBegin = source;
1914    const char* sourceEnd = source + strlen(source);
1915
1916    // Look for a version directive in the user-provided source.
1917    const char* versionBegin = strstr(source, "#version");
1918    const char* versionEnd = nullptr;
1919    if (versionBegin)
1920    {
1921        // If we found a directive, then scan for the end-of-line
1922        // after it, and use that to specify the slice.
1923        versionEnd = strchr(versionBegin, '\n');
1924        if (!versionEnd)
1925        {
1926            versionEnd = sourceEnd;
1927        }
1928        else
1929        {
1930            versionEnd = versionEnd + 1;
1931        }
1932    }
1933    else
1934    {
1935        // If we didn't find a directive, then treat it as being
1936        // a zero-byte slice at the start of the string
1937        versionBegin = sourceBegin;
1938        versionEnd = sourceBegin;
1939    }
1940
1941    enum
1942    {
1943        kMaxSourceStringCount = 16
1944    };
1945    const GLchar* sourceStrings[kMaxSourceStringCount];
1946    GLint sourceStringLengths[kMaxSourceStringCount];
1947
1948    int sourceStringCount = 0;
1949
1950    const char* stagePrelude = "\n";
1951    switch (stage)
1952    {
1953#define CASE(NAME)                                       \
1954    case GL_##NAME##_SHADER:                             \
1955        stagePrelude = "#define __GLSL_" #NAME "__ 1\n"; \
1956        break
1957
1958        CASE(VERTEX);
1959        CASE(TESS_CONTROL);
1960        CASE(TESS_EVALUATION);
1961        CASE(GEOMETRY);
1962        CASE(FRAGMENT);
1963        CASE(COMPUTE);
1964
1965#undef CASE
1966    }
1967
1968    const char* prelude = "#define __GLSL__ 1\n";
1969
1970#define ADD_SOURCE_STRING_SPAN(BEGIN, END)    \
1971    sourceStrings[sourceStringCount] = BEGIN; \
1972    sourceStringLengths[sourceStringCount++] = GLint(END - BEGIN) /* end */
1973
1974#define ADD_SOURCE_STRING(BEGIN)              \
1975    sourceStrings[sourceStringCount] = BEGIN; \
1976    sourceStringLengths[sourceStringCount++] = GLint(strlen(BEGIN)) /* end */
1977
1978    ADD_SOURCE_STRING_SPAN(versionBegin, versionEnd);
1979    ADD_SOURCE_STRING(stagePrelude);
1980    ADD_SOURCE_STRING(prelude);
1981    ADD_SOURCE_STRING_SPAN(sourceBegin, versionBegin);
1982    ADD_SOURCE_STRING_SPAN(versionEnd, sourceEnd);
1983
1984    auto shaderID = glCreateShader(stage);
1985    glShaderSource(shaderID, sourceStringCount, &sourceStrings[0], &sourceStringLengths[0]);
1986    glCompileShader(shaderID);
1987
1988    GLint success = GL_FALSE;
1989    glGetShaderiv(shaderID, GL_COMPILE_STATUS, &success);
1990    if (!success)
1991    {
1992        int maxSize = 0;
1993        glGetShaderiv(shaderID, GL_INFO_LOG_LENGTH, &maxSize);
1994
1995        auto infoBuffer = (char*)malloc(maxSize);
1996
1997        int infoSize = 0;
1998        glGetShaderInfoLog(shaderID, maxSize, &infoSize, infoBuffer);
1999        if (infoSize > 0)
2000        {
2001            fprintf(stderr, "%s", infoBuffer);
2002            ::OutputDebugStringA(infoBuffer);
2003        }
2004
2005        glDeleteShader(shaderID);
2006        return 0;
2007    }
2008
2009    return shaderID;
2010}
2011
2012// !!!!!!!!!!!!!!!!!!!!!!!!!!!! Renderer interface !!!!!!!!!!!!!!!!!!!!!!!!!!
2013
2014#ifdef _WIN32
2015LRESULT CALLBACK WindowProc(_In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam)
2016{
2017    return DefWindowProc(hwnd, uMsg, wParam, lParam);
2018}
2019#endif
2020
2021WindowHandle createWindow()
2022{
2023    WindowHandle window = {};
2024#ifdef _WIN32
2025    const wchar_t className[] = L"OpenGLContextWindow";
2026    static bool windowClassRegistered = false;
2027    HINSTANCE hInstance = GetModuleHandle(NULL);
2028    if (!windowClassRegistered)
2029    {
2030        windowClassRegistered = true;
2031        WNDCLASS wc = {};
2032        wc.lpfnWndProc = WindowProc;
2033        wc.hInstance = hInstance;
2034        wc.lpszClassName = className;
2035        RegisterClass(&wc);
2036    }
2037
2038    HWND hwnd = CreateWindowEx(
2039        0,                   // Optional window styles.
2040        className,           // Window class
2041        L"GLWindow",         // Window text
2042        WS_OVERLAPPEDWINDOW, // Window style
2043        // Size and position
2044        CW_USEDEFAULT,
2045        CW_USEDEFAULT,
2046        CW_USEDEFAULT,
2047        CW_USEDEFAULT,
2048        NULL,      // Parent window
2049        NULL,      // Menu
2050        hInstance, // Instance handle
2051        NULL       // Additional application data
2052    );
2053
2054    if (hwnd == NULL)
2055    {
2056        return window;
2057    }
2058    window = WindowHandle::FromHwnd(hwnd);
2059#endif
2060    return window;
2061}
2062
2063void destroyWindow(WindowHandle window)
2064{
2065#ifdef _WIN32
2066    DestroyWindow((HWND)window.handleValues[0]);
2067#endif
2068}
2069
2070GLDevice::GLDevice()
2071{
2072    m_weakRenderer = new WeakSink<GLDevice>(this);
2073}
2074
2075GLDevice::~GLDevice()
2076{
2077    // We can destroy things whilst in this state
2078    m_currentPipelineState.setNull();
2079    m_currentFramebuffer.setNull();
2080    if (glDeleteVertexArrays)
2081    {
2082        glDeleteVertexArrays(1, &m_vao);
2083    }
2084    if (m_glContext)
2085    {
2086        wglDeleteContext(m_glContext);
2087    }
2088    destroyWindow(m_windowHandle);
2089
2090    // By resetting the weak pointer, other objects accessing through WeakSink<GLDevice> will no
2091    // longer be able to access this object which is entering a 'being destroyed' to 'destroyed'
2092    // state
2093    if (m_weakRenderer)
2094    {
2095        SLANG_ASSERT(m_weakRenderer->get() == this);
2096        m_weakRenderer->detach();
2097    }
2098}
2099
2100HGLRC GLDevice::createGLContext(HDC hdc)
2101{
2102    PIXELFORMATDESCRIPTOR pixelFormatDesc = {sizeof(PIXELFORMATDESCRIPTOR)};
2103    pixelFormatDesc.nVersion = 1;
2104    pixelFormatDesc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
2105    pixelFormatDesc.iPixelType = PFD_TYPE_RGBA;
2106    pixelFormatDesc.cColorBits = 32;
2107    pixelFormatDesc.cDepthBits = 24;
2108    pixelFormatDesc.cStencilBits = 8;
2109    pixelFormatDesc.iLayerType = PFD_MAIN_PLANE;
2110    int pixelFormatIndex = ChoosePixelFormat(hdc, &pixelFormatDesc);
2111    SetPixelFormat(hdc, pixelFormatIndex, &pixelFormatDesc);
2112
2113    int attributeList[5];
2114
2115    attributeList[0] = WGL_CONTEXT_MAJOR_VERSION_ARB;
2116    attributeList[1] = 4;
2117    attributeList[2] = WGL_CONTEXT_MINOR_VERSION_ARB;
2118    attributeList[3] = 3;
2119    attributeList[4] = 0;
2120
2121    HGLRC newGLContext = wglCreateContextAttribsARB(hdc, m_glContext, attributeList);
2122    return newGLContext;
2123}
2124
2125SLANG_NO_THROW Result SLANG_MCALL GLDevice::initialize(const Desc& desc)
2126{
2127    SLANG_RETURN_ON_FAIL(slangContext.initialize(
2128        desc.slang,
2129        desc.extendedDescCount,
2130        desc.extendedDescs,
2131        SLANG_GLSL,
2132        "glsl_440",
2133        makeArray(slang::PreprocessorMacroDesc{"__GL__", "1"}).getView()));
2134
2135    SLANG_RETURN_ON_FAIL(RendererBase::initialize(desc));
2136
2137    // Initialize DeviceInfo
2138    {
2139        m_info.deviceType = DeviceType::OpenGl;
2140        m_info.bindingStyle = BindingStyle::OpenGl;
2141        m_info.projectionStyle = ProjectionStyle::OpenGl;
2142        m_info.apiName = "OpenGL";
2143        static const float kIdentity[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
2144        ::memcpy(m_info.identityProjectionMatrix, kIdentity, sizeof(kIdentity));
2145    }
2146
2147    m_windowHandle = createWindow();
2148    m_desc = desc;
2149
2150    m_hdc = ::GetDC((HWND)m_windowHandle.handleValues[0]);
2151
2152    PIXELFORMATDESCRIPTOR pixelFormatDesc = {sizeof(PIXELFORMATDESCRIPTOR)};
2153    pixelFormatDesc.nVersion = 1;
2154    pixelFormatDesc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
2155    pixelFormatDesc.iPixelType = PFD_TYPE_RGBA;
2156    pixelFormatDesc.cColorBits = 32;
2157    pixelFormatDesc.cDepthBits = 24;
2158    pixelFormatDesc.cStencilBits = 8;
2159    pixelFormatDesc.iLayerType = PFD_MAIN_PLANE;
2160
2161    int pixelFormatIndex = ChoosePixelFormat(m_hdc, &pixelFormatDesc);
2162    SetPixelFormat(m_hdc, pixelFormatIndex, &pixelFormatDesc);
2163    m_glContext = wglCreateContext(m_hdc);
2164    wglMakeCurrent(m_hdc, m_glContext);
2165
2166    auto renderer = glGetString(GL_RENDERER);
2167    m_info.adapterName = (char*)renderer;
2168
2169    if (desc.adapterLUID)
2170    {
2171        return SLANG_E_INVALID_ARG;
2172    }
2173
2174    if (m_desc.nvapiExtnSlot >= 0)
2175    {
2176        if (SLANG_FAILED(NVAPIUtil::initialize()))
2177        {
2178            return SLANG_E_NOT_AVAILABLE;
2179        }
2180    }
2181
2182
2183    auto extensions = glGetString(GL_EXTENSIONS);
2184
2185    // Load each of our extension functions by name
2186
2187#define LOAD_GL_EXTENSION_FUNC(NAME, TYPE) NAME = (TYPE)wglGetProcAddress(#NAME);
2188    MAP_GL_EXTENSION_FUNCS(LOAD_GL_EXTENSION_FUNC)
2189    MAP_WGL_EXTENSION_FUNCS(LOAD_GL_EXTENSION_FUNC)
2190#undef LOAD_GL_EXTENSION_FUNC
2191
2192    wglMakeCurrent(m_hdc, 0);
2193    wglDeleteContext(m_glContext);
2194    m_glContext = 0;
2195
2196    if (!wglCreateContextAttribsARB)
2197    {
2198        return SLANG_FAIL;
2199    }
2200
2201    m_glContext = createGLContext(m_hdc);
2202
2203    if (m_glContext == NULL)
2204    {
2205        return SLANG_FAIL;
2206    }
2207    wglMakeCurrent(m_hdc, m_glContext);
2208
2209    glDisable(GL_DEPTH_TEST);
2210    glDisable(GL_CULL_FACE);
2211
2212    if (!glGenVertexArrays)
2213        return SLANG_FAIL;
2214
2215    glGenVertexArrays(1, &m_vao);
2216    glBindVertexArray(m_vao);
2217
2218    if (glDebugMessageCallback)
2219    {
2220        glEnable(GL_DEBUG_OUTPUT);
2221        glDebugMessageCallback(staticDebugCallback, this);
2222    }
2223
2224    return SLANG_OK;
2225}
2226
2227void GLDevice::clearFrame(uint32_t mask, bool clearDepth, bool clearStencil)
2228{
2229    uint32_t clearMask = 0;
2230    if (clearDepth)
2231    {
2232        clearMask |= GL_DEPTH_BUFFER_BIT;
2233        glClearDepth(m_currentFramebuffer->m_depthStencilClearValue.depth);
2234    }
2235    if (clearStencil)
2236    {
2237        clearMask |= GL_STENCIL_BUFFER_BIT;
2238        glClearStencil(m_currentFramebuffer->m_depthStencilClearValue.stencil);
2239    }
2240    if (clearMask)
2241    {
2242        // If clear value for all attachments are the same, issue one `glClear` command.
2243        if (m_currentFramebuffer->m_sameClearValues &&
2244            m_currentFramebuffer->m_colorClearValues.getCount() > 0)
2245        {
2246            ShortList<GLenum> clearBuffers;
2247            auto clearColor = m_currentFramebuffer->m_colorClearValues[0];
2248            glClearColor(
2249                clearColor.floatValues[0],
2250                clearColor.floatValues[1],
2251                clearColor.floatValues[2],
2252                clearColor.floatValues[3]);
2253            for (Index i = 0; i < m_currentFramebuffer->m_colorClearValues.getCount(); i++)
2254            {
2255                if (mask & uint32_t(1 << i))
2256                    clearBuffers.add(GLenum(GL_COLOR_ATTACHMENT0 + i));
2257            }
2258            if (clearBuffers.getCount())
2259            {
2260                glDrawBuffers(
2261                    (GLsizei)clearBuffers.getCount(),
2262                    clearBuffers.getArrayView().getBuffer());
2263                clearMask |= GL_COLOR_BUFFER_BIT;
2264            }
2265            glClear(clearMask);
2266            glDrawBuffers(
2267                (GLsizei)m_currentFramebuffer->m_drawBuffers.getCount(),
2268                m_currentFramebuffer->m_drawBuffers.getArrayView().getBuffer());
2269            return;
2270        }
2271        // If clear values are different, clear attachments separately.
2272        for (Index i = 0; i < m_currentFramebuffer->m_colorClearValues.getCount(); i++)
2273        {
2274            if (mask & uint32_t(1 << i))
2275            {
2276                GLenum drawBuffer = GLenum(GL_COLOR_ATTACHMENT0 + i);
2277                glDrawBuffers(1, &drawBuffer);
2278                auto clearColor = m_currentFramebuffer->m_colorClearValues[i];
2279                glClearColor(
2280                    clearColor.floatValues[0],
2281                    clearColor.floatValues[1],
2282                    clearColor.floatValues[2],
2283                    clearColor.floatValues[3]);
2284                glClear(GL_COLOR_BUFFER_BIT);
2285            }
2286        }
2287        // Clear depth/stencil attachments.
2288        glClear(clearMask);
2289        glDrawBuffers(
2290            (GLsizei)m_currentFramebuffer->m_drawBuffers.getCount(),
2291            m_currentFramebuffer->m_drawBuffers.getArrayView().getBuffer());
2292    }
2293}
2294
2295SLANG_NO_THROW Result SLANG_MCALL GLDevice::createSwapchain(
2296    const ISwapchain::Desc& desc,
2297    WindowHandle window,
2298    ISwapchain** outSwapchain)
2299{
2300    RefPtr<SwapchainImpl> swapchain = new SwapchainImpl();
2301    SLANG_RETURN_ON_FAIL(swapchain->init(this, desc, window));
2302    returnComPtr(outSwapchain, swapchain);
2303    wglMakeCurrent(m_hdc, m_glContext);
2304    return SLANG_OK;
2305}
2306
2307SLANG_NO_THROW Result SLANG_MCALL GLDevice::createFramebufferLayout(
2308    const IFramebufferLayout::Desc& desc,
2309    IFramebufferLayout** outLayout)
2310{
2311    RefPtr<FramebufferLayoutImpl> layout = new FramebufferLayoutImpl();
2312    layout->m_renderTargets.setCount(desc.renderTargetCount);
2313    for (GfxIndex i = 0; i < desc.renderTargetCount; i++)
2314    {
2315        layout->m_renderTargets[i] = desc.renderTargets[i];
2316    }
2317
2318    if (desc.depthStencil)
2319    {
2320        layout->m_hasDepthStencil = true;
2321        layout->m_depthStencil = *desc.depthStencil;
2322    }
2323    else
2324    {
2325        layout->m_hasDepthStencil = false;
2326    }
2327    returnComPtr(outLayout, layout);
2328    return SLANG_OK;
2329}
2330
2331SLANG_NO_THROW Result SLANG_MCALL
2332GLDevice::createFramebuffer(const IFramebuffer::Desc& desc, IFramebuffer** outFramebuffer)
2333{
2334    RefPtr<FramebufferImpl> framebuffer = new FramebufferImpl(m_weakRenderer);
2335    framebuffer->renderTargetViews.setCount(desc.renderTargetCount);
2336    for (GfxIndex i = 0; i < desc.renderTargetCount; i++)
2337    {
2338        framebuffer->renderTargetViews[i] =
2339            static_cast<TextureViewImpl*>(desc.renderTargetViews[i]);
2340    }
2341    framebuffer->depthStencilView = static_cast<TextureViewImpl*>(desc.depthStencilView);
2342    framebuffer->createGLFramebuffer();
2343    returnComPtr(outFramebuffer, framebuffer);
2344    return SLANG_OK;
2345}
2346
2347void GLDevice::setFramebuffer(IFramebuffer* frameBuffer)
2348{
2349    m_currentFramebuffer = static_cast<FramebufferImpl*>(frameBuffer);
2350}
2351
2352void GLDevice::setStencilReference(uint32_t referenceValue)
2353{
2354    m_stencilRef = referenceValue;
2355    // TODO: actually set the stencil state.
2356}
2357
2358void GLDevice::copyBuffer(
2359    IBufferResource* dst,
2360    Offset dstOffset,
2361    IBufferResource* src,
2362    Offset srcOffset,
2363    Size size)
2364{
2365    auto dstImpl = static_cast<BufferResourceImpl*>(dst);
2366    auto srcImpl = static_cast<BufferResourceImpl*>(src);
2367    glBindBuffer(GL_COPY_READ_BUFFER, srcImpl->m_handle);
2368    glBindBuffer(GL_COPY_WRITE_BUFFER, dstImpl->m_handle);
2369    glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, srcOffset, dstOffset, size);
2370}
2371
2372SLANG_NO_THROW Result SLANG_MCALL GLDevice::readTextureResource(
2373    ITextureResource* texture,
2374    ResourceState state,
2375    ISlangBlob** outBlob,
2376    Size* outRowPitch,
2377    Size* outPixelSize)
2378{
2379    SLANG_UNUSED(state);
2380    auto resource = static_cast<TextureResourceImpl*>(texture);
2381    auto size = resource->getDesc()->size;
2382    size_t requiredSize = size.width * size.height * sizeof(uint32_t);
2383    if (outRowPitch)
2384        *outRowPitch = size.width * sizeof(uint32_t);
2385    if (outPixelSize)
2386        *outPixelSize = sizeof(uint32_t);
2387
2388    List<uint8_t> blobData;
2389
2390    blobData.setCount(requiredSize);
2391    auto buffer = blobData.begin();
2392    glBindTexture(resource->m_target, resource->m_handle);
2393    glGetTexImage(resource->m_target, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
2394
2395    // Flip pixels vertically in-place.
2396    for (int y = 0; y < size.height / 2; y++)
2397    {
2398        for (int x = 0; x < size.width; x++)
2399        {
2400            std::swap(
2401                *((uint32_t*)buffer + y * size.width + x),
2402                *((uint32_t*)buffer + (size.height - y - 1) * size.width + x));
2403        }
2404    }
2405
2406    auto blob = ListBlob::moveCreate(blobData);
2407    returnComPtr(outBlob, blob);
2408    return SLANG_OK;
2409}
2410
2411SLANG_NO_THROW Result SLANG_MCALL GLDevice::createTextureResource(
2412    const ITextureResource::Desc& descIn,
2413    const ITextureResource::SubresourceData* initData,
2414    ITextureResource** outResource)
2415{
2416    TextureResource::Desc srcDesc = fixupTextureDesc(descIn);
2417
2418    GlPixelFormat pixelFormat = _getGlPixelFormat(srcDesc.format);
2419    if (pixelFormat == GlPixelFormat::Unknown)
2420    {
2421        return SLANG_FAIL;
2422    }
2423
2424    const GlPixelFormatInfo& info = s_pixelFormatInfos[int(pixelFormat)];
2425
2426    const GLint internalFormat = info.internalFormat;
2427    const GLenum format = info.format;
2428    const GLenum formatType = info.formatType;
2429
2430    RefPtr<TextureResourceImpl> texture(new TextureResourceImpl(srcDesc, m_weakRenderer));
2431
2432    GLenum target = 0;
2433    GLuint handle = 0;
2434    glGenTextures(1, &handle);
2435
2436    const int effectiveArraySize = calcEffectiveArraySize(srcDesc);
2437
2438    // Set on texture so will be freed if failure
2439    texture->m_handle = handle;
2440
2441    // TODO: The logic below seems to be ignoring the row/layer stride of
2442    // the subresources that have been passed in, despite OpenGL having
2443    // the ability to set the image unpack stride, etc.
2444
2445    switch (srcDesc.type)
2446    {
2447    case IResource::Type::Texture1D:
2448        {
2449            if (srcDesc.arraySize > 0)
2450            {
2451                target = GL_TEXTURE_1D_ARRAY;
2452                glBindTexture(target, handle);
2453
2454                int slice = 0;
2455                for (int i = 0; i < effectiveArraySize; i++)
2456                {
2457                    for (int j = 0; j < srcDesc.numMipLevels; j++)
2458                    {
2459                        // TODO: Double-check this logic - we are passing in `i` as the height?
2460                        glTexImage2D(
2461                            target,
2462                            j,
2463                            internalFormat,
2464                            Math::Max(1, srcDesc.size.width >> j),
2465                            i,
2466                            0,
2467                            format,
2468                            formatType,
2469                            initData ? initData[slice++].data : nullptr);
2470                    }
2471                }
2472            }
2473            else
2474            {
2475                target = GL_TEXTURE_1D;
2476                glBindTexture(target, handle);
2477                for (int i = 0; i < srcDesc.numMipLevels; i++)
2478                {
2479                    glTexImage1D(
2480                        target,
2481                        i,
2482                        internalFormat,
2483                        Math::Max(1, srcDesc.size.width >> i),
2484                        0,
2485                        format,
2486                        formatType,
2487                        initData ? initData[i].data : nullptr);
2488                }
2489            }
2490            break;
2491        }
2492    case IResource::Type::TextureCube:
2493    case IResource::Type::Texture2D:
2494        {
2495            if (srcDesc.arraySize > 0)
2496            {
2497                if (srcDesc.type == IResource::Type::TextureCube)
2498                {
2499                    target = GL_TEXTURE_CUBE_MAP_ARRAY;
2500                }
2501                else
2502                {
2503                    target = GL_TEXTURE_2D_ARRAY;
2504                }
2505
2506                glBindTexture(target, handle);
2507
2508                int slice = 0;
2509                for (int i = 0; i < effectiveArraySize; i++)
2510                {
2511                    for (int j = 0; j < srcDesc.numMipLevels; j++)
2512                    {
2513                        const void* dataPtr = nullptr;
2514                        if (initData)
2515                        {
2516                            dataPtr = initData[slice].data;
2517                            ++slice;
2518                        }
2519                        glTexImage3D(
2520                            target,
2521                            j,
2522                            internalFormat,
2523                            Math::Max(1, srcDesc.size.width >> j),
2524                            Math::Max(1, srcDesc.size.height >> j),
2525                            slice,
2526                            0,
2527                            format,
2528                            formatType,
2529                            dataPtr);
2530                    }
2531                }
2532            }
2533            else
2534            {
2535                if (srcDesc.type == IResource::Type::TextureCube)
2536                {
2537                    target = GL_TEXTURE_CUBE_MAP;
2538                    glBindTexture(target, handle);
2539
2540                    int slice = 0;
2541                    for (int j = 0; j < 6; j++)
2542                    {
2543                        for (int i = 0; i < srcDesc.numMipLevels; i++)
2544                        {
2545                            glTexImage2D(
2546                                GL_TEXTURE_CUBE_MAP_POSITIVE_X + j,
2547                                i,
2548                                internalFormat,
2549                                Math::Max(1, srcDesc.size.width >> i),
2550                                Math::Max(1, srcDesc.size.height >> i),
2551                                0,
2552                                format,
2553                                formatType,
2554                                initData ? initData[slice++].data : nullptr);
2555                        }
2556                    }
2557                }
2558                else
2559                {
2560                    target = GL_TEXTURE_2D;
2561                    glBindTexture(target, handle);
2562                    for (int i = 0; i < srcDesc.numMipLevels; i++)
2563                    {
2564                        glTexImage2D(
2565                            target,
2566                            i,
2567                            internalFormat,
2568                            Math::Max(1, srcDesc.size.width >> i),
2569                            Math::Max(1, srcDesc.size.height >> i),
2570                            0,
2571                            format,
2572                            formatType,
2573                            initData ? initData[i].data : nullptr);
2574                    }
2575                }
2576            }
2577            break;
2578        }
2579    case IResource::Type::Texture3D:
2580        {
2581            target = GL_TEXTURE_3D;
2582            glBindTexture(target, handle);
2583            for (int i = 0; i < srcDesc.numMipLevels; i++)
2584            {
2585                glTexImage3D(
2586                    target,
2587                    i,
2588                    internalFormat,
2589                    Math::Max(1, srcDesc.size.width >> i),
2590                    Math::Max(1, srcDesc.size.height >> i),
2591                    Math::Max(1, srcDesc.size.depth >> i),
2592                    0,
2593                    format,
2594                    formatType,
2595                    initData ? initData[i].data : nullptr);
2596            }
2597            break;
2598        }
2599    default:
2600        return SLANG_FAIL;
2601    }
2602
2603    glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_REPEAT);
2604    glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_REPEAT);
2605    glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_REPEAT);
2606
2607    // Assume regular sampling (might be superseded - if a combined sampler wanted)
2608    glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
2609    glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2610    glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8.0f);
2611
2612    texture->m_target = target;
2613
2614    returnComPtr(outResource, texture);
2615    return SLANG_OK;
2616}
2617
2618static GLenum _calcUsage(ResourceState state)
2619{
2620    switch (state)
2621    {
2622    case ResourceState::ConstantBuffer:
2623        return GL_DYNAMIC_DRAW;
2624    default:
2625        return GL_STATIC_READ;
2626    }
2627}
2628
2629static GLenum _calcTarget(ResourceState state)
2630{
2631    switch (state)
2632    {
2633    case ResourceState::ConstantBuffer:
2634        return GL_UNIFORM_BUFFER;
2635    default:
2636        return GL_SHADER_STORAGE_BUFFER;
2637    }
2638}
2639
2640SLANG_NO_THROW Result SLANG_MCALL GLDevice::createBufferResource(
2641    const IBufferResource::Desc& descIn,
2642    const void* initData,
2643    IBufferResource** outResource)
2644{
2645    BufferResource::Desc desc = fixupBufferDesc(descIn);
2646
2647    const GLenum target = _calcTarget(desc.defaultState);
2648    const GLenum usage = _calcUsage(desc.defaultState);
2649
2650    GLuint bufferID = 0;
2651    glGenBuffers(1, &bufferID);
2652    glBindBuffer(target, bufferID);
2653
2654    glBufferData(target, descIn.sizeInBytes, initData, usage);
2655
2656    RefPtr<BufferResourceImpl> resourceImpl =
2657        new BufferResourceImpl(desc, m_weakRenderer, bufferID, target);
2658    returnComPtr(outResource, resourceImpl);
2659    return SLANG_OK;
2660}
2661
2662SLANG_NO_THROW Result SLANG_MCALL
2663GLDevice::createSamplerState(ISamplerState::Desc const& desc, ISamplerState** outSampler)
2664{
2665    GLuint samplerID;
2666    glCreateSamplers(1, &samplerID);
2667
2668    RefPtr<SamplerStateImpl> samplerImpl = new SamplerStateImpl();
2669    samplerImpl->m_samplerID = samplerID;
2670    returnComPtr(outSampler, samplerImpl);
2671    return SLANG_OK;
2672}
2673
2674SLANG_NO_THROW Result SLANG_MCALL GLDevice::createTextureView(
2675    ITextureResource* texture,
2676    IResourceView::Desc const& desc,
2677    IResourceView** outView)
2678{
2679    auto resourceImpl = static_cast<TextureResourceImpl*>(texture);
2680
2681    // TODO: actually do something?
2682
2683    RefPtr<TextureViewImpl> viewImpl = new TextureViewImpl();
2684    viewImpl->m_resource = resourceImpl;
2685    viewImpl->m_textureID = resourceImpl->m_handle;
2686    viewImpl->type = ResourceViewImpl::Type::Texture;
2687    viewImpl->m_target = resourceImpl->m_target;
2688    viewImpl->m_desc = desc;
2689
2690    if (desc.type == IResourceView::Type::ShaderResource)
2691    {
2692        viewImpl->access = GL_READ_ONLY;
2693        viewImpl->textureViewType = TextureViewImpl::TextureViewType::Texture;
2694    }
2695    else
2696    {
2697        viewImpl->access = GL_READ_WRITE;
2698        viewImpl->textureViewType = TextureViewImpl::TextureViewType::Image;
2699    }
2700    const GlPixelFormatInfo& info = s_pixelFormatInfos[int(_getGlPixelFormat(desc.format))];
2701    viewImpl->format = info.internalFormat;
2702    viewImpl->layered = GL_TRUE;
2703    viewImpl->level = 0;
2704    viewImpl->layer = 0;
2705    returnComPtr(outView, viewImpl);
2706    return SLANG_OK;
2707}
2708
2709SLANG_NO_THROW Result SLANG_MCALL GLDevice::createBufferView(
2710    IBufferResource* buffer,
2711    IBufferResource* counterBuffer,
2712    IResourceView::Desc const& desc,
2713    IResourceView** outView)
2714{
2715    auto resourceImpl = (BufferResourceImpl*)buffer;
2716
2717    // TODO: actually do something?
2718
2719    RefPtr<BufferViewImpl> viewImpl = new BufferViewImpl();
2720    viewImpl->type = ResourceViewImpl::Type::Buffer;
2721    viewImpl->m_resource = resourceImpl;
2722    viewImpl->m_bufferID = resourceImpl->m_handle;
2723    viewImpl->m_desc = desc;
2724
2725    returnComPtr(outView, viewImpl);
2726    return SLANG_OK;
2727}
2728
2729SLANG_NO_THROW Result SLANG_MCALL
2730GLDevice::createInputLayout(IInputLayout::Desc const& desc, IInputLayout** outLayout)
2731{
2732    RefPtr<InputLayoutImpl> inputLayout = new InputLayoutImpl;
2733
2734    auto inputElements = desc.inputElements;
2735    Int inputElementCount = desc.inputElementCount;
2736    inputLayout->m_attributeCount = inputElementCount;
2737    for (Int ii = 0; ii < inputElementCount; ++ii)
2738    {
2739        auto& inputAttr = inputElements[ii];
2740        auto& glAttr = inputLayout->m_attributes[ii];
2741
2742        glAttr.streamIndex = (GLuint)inputAttr.bufferSlotIndex;
2743        glAttr.format = getVertexAttributeFormat(inputAttr.format);
2744        glAttr.offset = (GLsizei)inputAttr.offset;
2745    }
2746
2747    Int inputStreamCount = desc.vertexStreamCount;
2748    inputLayout->m_streamCount = inputStreamCount;
2749    for (Int i = 0; i < inputStreamCount; ++i)
2750    {
2751        inputLayout->m_streams[i].stride = desc.vertexStreams[i].stride;
2752    }
2753
2754    returnComPtr(outLayout, inputLayout);
2755    return SLANG_OK;
2756}
2757
2758void* GLDevice::map(IBufferResource* bufferIn, MapFlavor flavor)
2759{
2760    BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(bufferIn);
2761
2762    // GLenum target = GL_UNIFORM_BUFFER;
2763
2764    GLuint access = 0;
2765    switch (flavor)
2766    {
2767    case MapFlavor::WriteDiscard:
2768    case MapFlavor::HostWrite:
2769        access = GL_WRITE_ONLY;
2770        break;
2771    case MapFlavor::HostRead:
2772        access = GL_READ_ONLY;
2773        break;
2774    }
2775
2776    glBindBuffer(buffer->m_target, buffer->m_handle);
2777
2778    return glMapBuffer(buffer->m_target, access);
2779}
2780
2781void GLDevice::unmap(IBufferResource* bufferIn, size_t offsetWritten, size_t sizeWritten)
2782{
2783    SLANG_UNUSED(offsetWritten);
2784    SLANG_UNUSED(sizeWritten);
2785    BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(bufferIn);
2786    glUnmapBuffer(buffer->m_target);
2787}
2788
2789void GLDevice::setPrimitiveTopology(PrimitiveTopology topology)
2790{
2791    GLenum glTopology = 0;
2792    switch (topology)
2793    {
2794#define CASE(NAME, VALUE)         \
2795    case PrimitiveTopology::NAME: \
2796        glTopology = VALUE;       \
2797        break
2798
2799        CASE(TriangleList, GL_TRIANGLES);
2800
2801#undef CASE
2802    }
2803    m_boundPrimitiveTopology = glTopology;
2804}
2805
2806void GLDevice::setVertexBuffers(
2807    GfxIndex startSlot,
2808    GfxCount slotCount,
2809    IBufferResource* const* buffers,
2810    const Offset* offsets)
2811{
2812    for (UInt ii = 0; ii < slotCount; ++ii)
2813    {
2814        UInt slot = startSlot + ii;
2815
2816        BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(buffers[ii]);
2817        GLuint bufferID = buffer ? buffer->m_handle : 0;
2818
2819        m_boundVertexStreamBuffers[slot] = bufferID;
2820        m_boundVertexStreamOffsets[slot] = offsets[ii];
2821    }
2822}
2823
2824void GLDevice::setIndexBuffer(IBufferResource* buffer, Format indexFormat, Offset offset)
2825{
2826    auto bufferImpl = static_cast<BufferResourceImpl*>(buffer);
2827    m_boundIndexBuffer = bufferImpl->m_handle;
2828    m_boundIndexBufferOffset = offset;
2829    m_boundIndexBufferSize = bufferImpl->m_size;
2830}
2831
2832void GLDevice::setViewports(GfxCount count, Viewport const* viewports)
2833{
2834    assert(count == 1);
2835    auto viewport = viewports[0];
2836    glViewport(
2837        (GLint)viewport.originX,
2838        (GLint)viewport.originY,
2839        (GLsizei)viewport.extentX,
2840        (GLsizei)viewport.extentY);
2841    glDepthRange(viewport.minZ, viewport.maxZ);
2842}
2843
2844void GLDevice::setScissorRects(GfxCount count, ScissorRect const* rects)
2845{
2846    assert(count <= 1);
2847    if (count)
2848    {
2849        // TODO: this isn't goign to be quite right because of the
2850        // flipped coordinate system in GL.
2851        //
2852        // The best way around this is probably to *always* render
2853        // things internally into textures with "flipped" conventions,
2854        // and then only deal with the flipping as part of a final
2855        // "present" step that copies to the primary back-buffer.
2856        //
2857        auto rect = rects[0];
2858        glScissor(
2859            GLint(rect.minX),
2860            GLint(rect.minY),
2861            GLsizei(rect.maxX - rect.minX),
2862            GLsizei(rect.maxY - rect.minY));
2863
2864        glEnable(GL_SCISSOR_TEST);
2865    }
2866    else
2867    {
2868        glDisable(GL_SCISSOR_TEST);
2869    }
2870}
2871
2872void GLDevice::setPipelineState(IPipelineState* state)
2873{
2874    auto pipelineStateImpl = static_cast<PipelineStateImpl*>(state);
2875
2876    m_currentPipelineState = pipelineStateImpl;
2877
2878    auto program = static_cast<ShaderProgramImpl*>(pipelineStateImpl->m_program.Ptr());
2879    GLuint programID = program ? program->m_id : 0;
2880    glUseProgram(programID);
2881}
2882
2883void GLDevice::draw(GfxCount vertexCount, GfxIndex startVertex = 0)
2884{
2885    flushStateForDraw();
2886
2887    glDrawArrays(m_boundPrimitiveTopology, (GLint)startVertex, (GLsizei)vertexCount);
2888}
2889
2890void GLDevice::drawIndexed(GfxCount indexCount, GfxIndex startIndex, GfxIndex baseVertex)
2891{
2892    flushStateForDraw();
2893
2894    glDrawElementsBaseVertex(
2895        m_boundPrimitiveTopology,
2896        (GLsizei)indexCount,
2897        GL_UNSIGNED_INT,
2898        (GLvoid*)(startIndex * sizeof(uint32_t)),
2899        (GLint)baseVertex);
2900}
2901
2902void GLDevice::drawInstanced(
2903    GfxCount vertexCount,
2904    GfxCount instanceCount,
2905    GfxIndex startVertex,
2906    GfxIndex startInstanceLocation)
2907{
2908    SLANG_UNIMPLEMENTED_X("drawInstanced");
2909}
2910
2911void GLDevice::drawIndexedInstanced(
2912    GfxCount indexCount,
2913    GfxCount instanceCount,
2914    GfxIndex startIndexLocation,
2915    GfxIndex baseVertexLocation,
2916    GfxIndex startInstanceLocation)
2917{
2918    SLANG_UNIMPLEMENTED_X("drawIndexedInstanced");
2919}
2920
2921void GLDevice::dispatchCompute(int x, int y, int z)
2922{
2923    glDispatchCompute(x, y, z);
2924}
2925
2926Result GLDevice::createProgram(
2927    const IShaderProgram::Desc& desc,
2928    IShaderProgram** outProgram,
2929    ISlangBlob** outDiagnosticBlob)
2930{
2931    if (desc.slangGlobalScope->getSpecializationParamCount() != 0)
2932    {
2933        // For a specializable program, we don't invoke any actual slang compilation yet.
2934        RefPtr<ShaderProgramImpl> shaderProgram = new ShaderProgramImpl(m_weakRenderer, 0);
2935        shaderProgram->init(desc);
2936        returnComPtr(outProgram, shaderProgram);
2937        return SLANG_OK;
2938    }
2939
2940    auto programID = glCreateProgram();
2941    auto programLayout = desc.slangGlobalScope->getLayout();
2942    ShortList<GLuint> shaderIDs;
2943    for (SlangUInt i = 0; i < programLayout->getEntryPointCount(); i++)
2944    {
2945        ComPtr<ISlangBlob> kernelCode;
2946        ComPtr<ISlangBlob> diagnostics;
2947        auto compileResult = getEntryPointCodeFromShaderCache(
2948            desc.slangGlobalScope,
2949            i,
2950            0,
2951            kernelCode.writeRef(),
2952            diagnostics.writeRef());
2953        if (diagnostics)
2954        {
2955            getDebugCallback()->handleMessage(
2956                compileResult == SLANG_OK ? DebugMessageType::Warning : DebugMessageType::Error,
2957                DebugMessageSource::Slang,
2958                (char*)diagnostics->getBufferPointer());
2959            if (outDiagnosticBlob)
2960                returnComPtr(outDiagnosticBlob, diagnostics);
2961        }
2962        SLANG_RETURN_ON_FAIL(compileResult);
2963        GLenum glShaderType = 0;
2964        auto stage = programLayout->getEntryPointByIndex(i)->getStage();
2965        switch (stage)
2966        {
2967        case SLANG_STAGE_COMPUTE:
2968            glShaderType = GL_COMPUTE_SHADER;
2969            break;
2970        case SLANG_STAGE_VERTEX:
2971            glShaderType = GL_VERTEX_SHADER;
2972            break;
2973        case SLANG_STAGE_FRAGMENT:
2974            glShaderType = GL_FRAGMENT_SHADER;
2975            break;
2976        case SLANG_STAGE_GEOMETRY:
2977            glShaderType = GL_GEOMETRY_SHADER;
2978            break;
2979        case SLANG_STAGE_DOMAIN:
2980            glShaderType = GL_TESS_CONTROL_SHADER;
2981            break;
2982        case SLANG_STAGE_HULL:
2983            glShaderType = GL_TESS_EVALUATION_SHADER;
2984            break;
2985        default:
2986            SLANG_ASSERT(!"unsupported shader type.");
2987            break;
2988        }
2989        auto shaderID = loadShader(glShaderType, (char const*)kernelCode->getBufferPointer());
2990        shaderIDs.add(shaderID);
2991        glAttachShader(programID, shaderID);
2992    }
2993    glLinkProgram(programID);
2994    for (auto shaderID : shaderIDs)
2995        glDeleteShader(shaderID);
2996    GLint success = GL_FALSE;
2997    glGetProgramiv(programID, GL_LINK_STATUS, &success);
2998    if (!success)
2999    {
3000        int maxSize = 0;
3001        glGetProgramiv(programID, GL_INFO_LOG_LENGTH, &maxSize);
3002
3003        auto infoBuffer = (char*)::malloc(maxSize);
3004
3005        int infoSize = 0;
3006        glGetProgramInfoLog(programID, maxSize, &infoSize, infoBuffer);
3007        if (infoSize > 0)
3008        {
3009            fprintf(stderr, "%s", infoBuffer);
3010            OutputDebugStringA(infoBuffer);
3011        }
3012
3013        ::free(infoBuffer);
3014
3015        glDeleteProgram(programID);
3016        return SLANG_FAIL;
3017    }
3018
3019    RefPtr<ShaderProgramImpl> program = new ShaderProgramImpl(m_weakRenderer, programID);
3020    program->slangGlobalScope = desc.slangGlobalScope;
3021    returnComPtr(outProgram, program);
3022    return SLANG_OK;
3023}
3024
3025Result GLDevice::createGraphicsPipelineState(
3026    const GraphicsPipelineStateDesc& inDesc,
3027    IPipelineState** outState)
3028{
3029    GraphicsPipelineStateDesc desc = inDesc;
3030
3031    auto programImpl = (ShaderProgramImpl*)desc.program;
3032    auto inputLayoutImpl = (InputLayoutImpl*)desc.inputLayout;
3033
3034    RefPtr<PipelineStateImpl> pipelineStateImpl = new PipelineStateImpl();
3035    pipelineStateImpl->m_inputLayout = inputLayoutImpl;
3036    pipelineStateImpl->init(desc);
3037    returnComPtr(outState, pipelineStateImpl);
3038    return SLANG_OK;
3039}
3040
3041Result GLDevice::createComputePipelineState(
3042    const ComputePipelineStateDesc& inDesc,
3043    IPipelineState** outState)
3044{
3045    ComputePipelineStateDesc desc = inDesc;
3046
3047    auto programImpl = (ShaderProgramImpl*)desc.program;
3048
3049    RefPtr<PipelineStateImpl> pipelineStateImpl = new PipelineStateImpl();
3050    pipelineStateImpl->m_program = programImpl;
3051    pipelineStateImpl->init(desc);
3052    returnComPtr(outState, pipelineStateImpl);
3053    return SLANG_OK;
3054}
3055
3056Result GLDevice::createShaderObjectLayout(
3057    slang::ISession* session,
3058    slang::TypeLayoutReflection* typeLayout,
3059    ShaderObjectLayoutBase** outLayout)
3060{
3061    RefPtr<ShaderObjectLayoutImpl> layout;
3062    SLANG_RETURN_ON_FAIL(
3063        ShaderObjectLayoutImpl::createForElementType(this, session, typeLayout, layout.writeRef()));
3064    returnRefPtrMove(outLayout, layout);
3065    return SLANG_OK;
3066}
3067
3068Result GLDevice::createShaderObject(ShaderObjectLayoutBase* layout, IShaderObject** outObject)
3069{
3070    RefPtr<ShaderObjectImpl> shaderObject;
3071    SLANG_RETURN_ON_FAIL(ShaderObjectImpl::create(
3072        this,
3073        static_cast<ShaderObjectLayoutImpl*>(layout),
3074        shaderObject.writeRef()));
3075    returnComPtr(outObject, shaderObject);
3076    return SLANG_OK;
3077}
3078
3079Result GLDevice::createMutableShaderObject(
3080    ShaderObjectLayoutBase* layout,
3081    IShaderObject** outObject)
3082{
3083    auto layoutImpl = static_cast<ShaderObjectLayoutImpl*>(layout);
3084
3085    RefPtr<MutableShaderObjectImpl> result = new MutableShaderObjectImpl();
3086    SLANG_RETURN_ON_FAIL(result->init(this, layoutImpl));
3087    returnComPtr(outObject, result);
3088
3089    return SLANG_OK;
3090}
3091
3092Result GLDevice::createRootShaderObject(IShaderProgram* program, ShaderObjectBase** outObject)
3093{
3094    auto programImpl = static_cast<ShaderProgramImpl*>(program);
3095    RefPtr<RootShaderObjectImpl> shaderObject;
3096    RefPtr<RootShaderObjectLayoutImpl> rootLayout;
3097    SLANG_RETURN_ON_FAIL(RootShaderObjectLayoutImpl::create(
3098        this,
3099        programImpl->slangGlobalScope,
3100        programImpl->slangGlobalScope->getLayout(),
3101        rootLayout.writeRef()));
3102    SLANG_RETURN_ON_FAIL(
3103        RootShaderObjectImpl::create(this, rootLayout.Ptr(), shaderObject.writeRef()));
3104    returnRefPtrMove(outObject, shaderObject);
3105    return SLANG_OK;
3106}
3107
3108void GLDevice::bindRootShaderObject(IShaderObject* shaderObject)
3109{
3110    RootShaderObjectImpl* rootShaderObjectImpl = static_cast<RootShaderObjectImpl*>(shaderObject);
3111    RefPtr<PipelineStateBase> specializedPipeline;
3112    maybeSpecializePipeline(m_currentPipelineState, rootShaderObjectImpl, specializedPipeline);
3113    setPipelineState(specializedPipeline.Ptr());
3114
3115    m_rootBindingState.imageBindings.clear();
3116    m_rootBindingState.samplerBindings.clear();
3117    m_rootBindingState.textureBindings.clear();
3118    m_rootBindingState.storageBufferBindings.clear();
3119    m_rootBindingState.uniformBufferBindings.clear();
3120    static_cast<ShaderObjectImpl*>(shaderObject)->bindObject(this, &m_rootBindingState);
3121    for (Index i = 0; i < m_rootBindingState.imageBindings.getCount(); i++)
3122    {
3123        auto binding = m_rootBindingState.imageBindings[i];
3124        glBindImageTexture(
3125            (GLuint)i,
3126            binding->m_textureID,
3127            binding->level,
3128            binding->layered,
3129            binding->layer,
3130            binding->access,
3131            binding->format);
3132    }
3133    for (Index i = 0; i < m_rootBindingState.textureBindings.getCount(); i++)
3134    {
3135        glActiveTexture((GLenum)(GL_TEXTURE0 + i));
3136        auto binding = m_rootBindingState.textureBindings[i];
3137        if (binding)
3138            glBindTexture(binding->m_target, binding->m_textureID);
3139        glBindSampler((GLuint)i, m_rootBindingState.samplerBindings[i]);
3140    }
3141    for (Index i = 0; i < m_rootBindingState.storageBufferBindings.getCount(); i++)
3142    {
3143        glBindBufferBase(
3144            GL_SHADER_STORAGE_BUFFER,
3145            (GLuint)i,
3146            m_rootBindingState.storageBufferBindings[i]);
3147    }
3148    for (Index i = 0; i < m_rootBindingState.uniformBufferBindings.getCount(); i++)
3149    {
3150        glBindBufferBase(GL_UNIFORM_BUFFER, (GLuint)i, m_rootBindingState.uniformBufferBindings[i]);
3151    }
3152}
3153
3154SlangResult SLANG_MCALL createGLDevice(const IDevice::Desc* desc, IDevice** outRenderer)
3155{
3156    RefPtr<GLDevice> result = new GLDevice();
3157    SLANG_RETURN_ON_FAIL(result->initialize(*desc));
3158    returnComPtr(outRenderer, result);
3159    return SLANG_OK;
3160}
3161
3162} // namespace gfx
3163
3164#else
3165
3166namespace gfx
3167{
3168SlangResult SLANG_MCALL createGLDevice(const IDevice::Desc* desc, IDevice** outRenderer)
3169{
3170    *outRenderer = nullptr;
3171    return SLANG_FAIL;
3172}
3173} // namespace gfx
3174#endif