From 337c276ccb49123189615411a9815ba6665f171b Mon Sep 17 00:00:00 2001
From: Jack Andersen <jackoalan@gmail.com>
Date: Fri, 19 Jan 2018 17:02:29 -1000
Subject: [PATCH] WTF

---
 CMakeLists.txt                                |   1 +
 .../boo/graphicsdev/IGraphicsCommandQueue.hpp |   1 +
 .../boo/graphicsdev/IGraphicsDataFactory.hpp  |   1 +
 include/boo/graphicsdev/Vulkan.hpp            |   1 +
 lib/graphicsdev/Common.cpp                    |  17 ++
 lib/graphicsdev/Common.hpp                    |   2 +
 lib/graphicsdev/D3D11.cpp                     |  14 +-
 lib/graphicsdev/D3D12.cpp                     |  39 ++---
 lib/graphicsdev/GL.cpp                        | 158 ++++++++++++++++--
 lib/graphicsdev/Vulkan.cpp                    |   2 +
 lib/win/ApplicationWin32.cpp                  |  10 +-
 lib/win/WinCommon.hpp                         |  12 ++
 lib/win/WindowWin32.cpp                       |  77 +++++++--
 test/main.cpp                                 |   5 +-
 14 files changed, 287 insertions(+), 53 deletions(-)
 create mode 100644 lib/graphicsdev/Common.cpp

diff --git a/CMakeLists.txt b/CMakeLists.txt
index b6fc97d..7032bd4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -278,6 +278,7 @@ add_library(boo
             include/boo/graphicsdev/IGraphicsDataFactory.hpp
             include/boo/graphicsdev/IGraphicsCommandQueue.hpp
             lib/graphicsdev/Common.hpp
+            lib/graphicsdev/Common.cpp
             include/boo/audiodev/IAudioSubmix.hpp
             include/boo/audiodev/IAudioVoice.hpp
             include/boo/audiodev/IMIDIPort.hpp
diff --git a/include/boo/graphicsdev/IGraphicsCommandQueue.hpp b/include/boo/graphicsdev/IGraphicsCommandQueue.hpp
index 858a4df..56fd830 100644
--- a/include/boo/graphicsdev/IGraphicsCommandQueue.hpp
+++ b/include/boo/graphicsdev/IGraphicsCommandQueue.hpp
@@ -37,6 +37,7 @@ struct IGraphicsCommandQueue
     virtual void resolveDisplay(const ObjToken<ITextureR>& source)=0;
     virtual void execute()=0;
 
+    virtual void startRenderer()=0;
     virtual void stopRenderer()=0;
 };
 
diff --git a/include/boo/graphicsdev/IGraphicsDataFactory.hpp b/include/boo/graphicsdev/IGraphicsDataFactory.hpp
index 23c8ab5..f2da47e 100644
--- a/include/boo/graphicsdev/IGraphicsDataFactory.hpp
+++ b/include/boo/graphicsdev/IGraphicsDataFactory.hpp
@@ -61,6 +61,7 @@ enum class TextureFormat
 {
     RGBA8,
     I8,
+    I16,
     DXT1,
     PVRTC4
 };
diff --git a/include/boo/graphicsdev/Vulkan.hpp b/include/boo/graphicsdev/Vulkan.hpp
index 417b3a7..34e6670 100644
--- a/include/boo/graphicsdev/Vulkan.hpp
+++ b/include/boo/graphicsdev/Vulkan.hpp
@@ -87,6 +87,7 @@ struct VulkanContext
     VkSampleCountFlags m_sampleCountColor = VK_SAMPLE_COUNT_1_BIT;
     VkSampleCountFlags m_sampleCountDepth = VK_SAMPLE_COUNT_1_BIT;
     float m_anisotropy = 1.f;
+    bool m_deepColor = false;
 
     std::unordered_map<uint32_t, VkSampler> m_samplers;
 
diff --git a/lib/graphicsdev/Common.cpp b/lib/graphicsdev/Common.cpp
new file mode 100644
index 0000000..0105056
--- /dev/null
+++ b/lib/graphicsdev/Common.cpp
@@ -0,0 +1,17 @@
+#include "Common.hpp"
+
+namespace boo
+{
+
+void UpdateGammaLUT(ITextureD* tex, float gamma)
+{
+    void* data = tex->map(65536 * 2);
+    for (int i=0 ; i<65536 ; ++i)
+    {
+        float level = std::pow(i / 65535.f, gamma);
+        reinterpret_cast<uint16_t*>(data)[i] = level * 65535.f;
+    }
+    tex->unmap();
+}
+
+}
diff --git a/lib/graphicsdev/Common.hpp b/lib/graphicsdev/Common.hpp
index 837d4a7..baafe7e 100644
--- a/lib/graphicsdev/Common.hpp
+++ b/lib/graphicsdev/Common.hpp
@@ -195,6 +195,8 @@ public:
     Token lock() { return Token(this); }
 };
 
+void UpdateGammaLUT(ITextureD* tex, float gamma);
+
 }
 
 #endif // BOO_GRAPHICSDEV_COMMON_HPP
diff --git a/lib/graphicsdev/D3D11.cpp b/lib/graphicsdev/D3D11.cpp
index 8df7910..c47b446 100644
--- a/lib/graphicsdev/D3D11.cpp
+++ b/lib/graphicsdev/D3D11.cpp
@@ -302,7 +302,7 @@ class D3D11TextureR : public GraphicsDataNode<ITextureR>
 
     void Setup(D3D11Context* ctx)
     {
-        ThrowIfFailed(ctx->m_dev->CreateTexture2D(&CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, m_width, m_height,
+        ThrowIfFailed(ctx->m_dev->CreateTexture2D(&CD3D11_TEXTURE2D_DESC(ctx->m_fbFormat, m_width, m_height,
             1, 1, D3D11_BIND_RENDER_TARGET, D3D11_USAGE_DEFAULT, 0, m_samples), nullptr, &m_colorTex));
         ThrowIfFailed(ctx->m_dev->CreateTexture2D(&CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_D24_UNORM_S8_UINT, m_width, m_height,
             1, 1, D3D11_BIND_DEPTH_STENCIL, D3D11_USAGE_DEFAULT, 0, m_samples), nullptr, &m_depthTex));
@@ -328,7 +328,7 @@ class D3D11TextureR : public GraphicsDataNode<ITextureR>
 
         for (size_t i=0 ; i<m_colorBindCount ; ++i)
         {
-            ThrowIfFailed(ctx->m_dev->CreateTexture2D(&CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, m_width, m_height,
+            ThrowIfFailed(ctx->m_dev->CreateTexture2D(&CD3D11_TEXTURE2D_DESC(ctx->m_fbFormat, m_width, m_height,
                 1, 1, D3D11_BIND_SHADER_RESOURCE, D3D11_USAGE_DEFAULT, 0, 1), nullptr, &m_colorBindTex[i]));
             ThrowIfFailed(ctx->m_dev->CreateShaderResourceView(m_colorBindTex[i].Get(),
                 &CD3D11_SHADER_RESOURCE_VIEW_DESC(m_colorBindTex[i].Get(), D3D11_SRV_DIMENSION_TEXTURE2D), &m_colorSrv[i]));
@@ -965,7 +965,7 @@ struct D3D11CommandQueue : IGraphicsCommandQueue
                 {
                     self->m_windowCtx->m_swapChain->ResizeBuffers(2,
                         self->m_windowCtx->width, self->m_windowCtx->height,
-                        DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH);
+                        self->m_ctx->m_fbFormat, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH);
                     self->m_windowCtx->m_needsResize = false;
                     CmdList.reset();
                     continue;
@@ -984,7 +984,7 @@ struct D3D11CommandQueue : IGraphicsCommandQueue
 
                 ID3D11Texture2D* src = csource->m_colorTex.Get();
                 if (csource->m_samples > 1)
-                    self->m_ctx->m_devCtx->ResolveSubresource(dest.Get(), 0, src, 0, DXGI_FORMAT_R8G8B8A8_UNORM);
+                    self->m_ctx->m_devCtx->ResolveSubresource(dest.Get(), 0, src, 0, self->m_ctx->m_fbFormat);
                 else
                     self->m_ctx->m_devCtx->CopyResource(dest.Get(), src);
 
@@ -1005,6 +1005,8 @@ struct D3D11CommandQueue : IGraphicsCommandQueue
         ThrowIfFailed(ctx->m_dev->CreateDeferredContext1(0, &m_deferredCtx));
     }
 
+    void startRenderer() {}
+
     void stopRenderer()
     {
         m_running = false;
@@ -1122,7 +1124,7 @@ struct D3D11CommandQueue : IGraphicsCommandQueue
             if (tex->m_samples > 1)
             {
                 m_deferredCtx->ResolveSubresource(tex->m_colorBindTex[bindIdx].Get(), 0, tex->m_colorTex.Get(), 0,
-                                                  DXGI_FORMAT_R8G8B8A8_UNORM);
+                                                  m_ctx->m_fbFormat);
             }
             else
             {
@@ -1248,7 +1250,7 @@ public:
     {
         UINT qLevels;
         while (SUCCEEDED(ctx->m_dev->CheckMultisampleQualityLevels
-                         (DXGI_FORMAT_R8G8B8A8_UNORM, m_ctx->m_sampleCount, &qLevels)) && !qLevels)
+                         (m_ctx->m_fbFormat, m_ctx->m_sampleCount, &qLevels)) && !qLevels)
             m_ctx->m_sampleCount = flp2(m_ctx->m_sampleCount - 1);
     }
 
diff --git a/lib/graphicsdev/D3D12.cpp b/lib/graphicsdev/D3D12.cpp
index 6610f59..0a69433 100644
--- a/lib/graphicsdev/D3D12.cpp
+++ b/lib/graphicsdev/D3D12.cpp
@@ -447,7 +447,7 @@ class D3D12TextureR : public GraphicsDataNode<ITextureR>
         {
             rtvDim = D3D12_RTV_DIMENSION_TEXTURE2DMS;
             dsvDim = D3D12_DSV_DIMENSION_TEXTURE2DMS;
-            rtvresdesc = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R8G8B8A8_UNORM, m_width, m_height, 1, 1, m_samples,
+            rtvresdesc = CD3DX12_RESOURCE_DESC::Tex2D(ctx->RGBATex2DFBViewDesc.Format, m_width, m_height, 1, 1, m_samples,
                 D3D11_STANDARD_MULTISAMPLE_PATTERN, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, D3D12_TEXTURE_LAYOUT_UNKNOWN,
                 D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT);
             dsvresdesc = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R24G8_TYPELESS, m_width, m_height, 1, 1, m_samples,
@@ -458,19 +458,19 @@ class D3D12TextureR : public GraphicsDataNode<ITextureR>
         {
             rtvDim = D3D12_RTV_DIMENSION_TEXTURE2D;
             dsvDim = D3D12_DSV_DIMENSION_TEXTURE2D;
-            rtvresdesc = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R8G8B8A8_UNORM, m_width, m_height, 1, 1, 1,
+            rtvresdesc = CD3DX12_RESOURCE_DESC::Tex2D(ctx->RGBATex2DFBViewDesc.Format, m_width, m_height, 1, 1, 1,
                 0, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET);
             dsvresdesc = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R24G8_TYPELESS, m_width, m_height, 1, 1, 1,
                 0, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL);
         }
 
-        cbindresdesc = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R8G8B8A8_UNORM, m_width, m_height, 1, 1, 1,
+        cbindresdesc = CD3DX12_RESOURCE_DESC::Tex2D(ctx->RGBATex2DFBViewDesc.Format, m_width, m_height, 1, 1, 1,
             0, D3D12_RESOURCE_FLAG_NONE);
         dbindresdesc = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R24G8_TYPELESS, m_width, m_height, 1, 1, 1,
             0, D3D12_RESOURCE_FLAG_NONE);
 
         D3D12_CLEAR_VALUE colorClear = {};
-        colorClear.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+        colorClear.Format = ctx->RGBATex2DFBViewDesc.Format;
         ThrowIfFailed(ctx->m_dev->CreateCommittedResource(&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE,
             &rtvresdesc, D3D12_RESOURCE_STATE_RENDER_TARGET, &colorClear,
             __uuidof(ID3D12Resource), &m_colorTex));
@@ -481,7 +481,7 @@ class D3D12TextureR : public GraphicsDataNode<ITextureR>
             &dsvresdesc, D3D12_RESOURCE_STATE_DEPTH_WRITE, &depthClear,
             __uuidof(ID3D12Resource), &m_depthTex));
 
-        D3D12_RENDER_TARGET_VIEW_DESC rtvvdesc = {DXGI_FORMAT_R8G8B8A8_UNORM, rtvDim};
+        D3D12_RENDER_TARGET_VIEW_DESC rtvvdesc = {ctx->RGBATex2DFBViewDesc.Format, rtvDim};
         ctx->m_dev->CreateRenderTargetView(m_colorTex.Get(), &rtvvdesc, m_rtvHeap->GetCPUDescriptorHandleForHeapStart());
 
         D3D12_DEPTH_STENCIL_VIEW_DESC dsvvdesc = {DXGI_FORMAT_D24_UNORM_S8_UINT, dsvDim};
@@ -746,7 +746,7 @@ class D3D12ShaderPipeline : public GraphicsDataNode<IShaderPipeline>
         desc.SampleMask = UINT_MAX;
         desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
         desc.NumRenderTargets = 1;
-        desc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
+        desc.RTVFormats[0] = ctx->RGBATex2DFBViewDesc.Format;
         desc.DSVFormat = DXGI_FORMAT_D24_UNORM_S8_UINT;
         desc.SampleDesc.Count = ctx->m_sampleCount;
         desc.SampleDesc.Quality = D3D11_STANDARD_MULTISAMPLE_PATTERN;
@@ -851,17 +851,6 @@ static ID3D12Resource* GetBufferGPUResource(const IGraphicsBuffer* buf, int idx,
     }
 }
 
-static const struct RGBATex2DNoMipViewDesc : D3D12_SHADER_RESOURCE_VIEW_DESC
-{
-    RGBATex2DNoMipViewDesc()
-    {
-        Format = DXGI_FORMAT_R8G8B8A8_UNORM;
-        ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
-        Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
-        Texture2D = {UINT(0), UINT(1), UINT(0), 0.0f};
-    }
-} RGBATex2DNoMipViewDesc;
-
 static const struct RGBATex2DDepthViewDesc : D3D12_SHADER_RESOURCE_VIEW_DESC
 {
     RGBATex2DDepthViewDesc()
@@ -928,7 +917,7 @@ static const struct GreyTex2DArrayViewDesc : D3D12_SHADER_RESOURCE_VIEW_DESC
     }
 } GreyTex2DArrayViewDesc;
 
-static ID3D12Resource* GetTextureGPUResource(const ITexture* tex, int idx, int bindIdx, bool depth,
+static ID3D12Resource* GetTextureGPUResource(D3D12Context* ctx, const ITexture* tex, int idx, int bindIdx, bool depth,
                                              D3D12_SHADER_RESOURCE_VIEW_DESC& descOut)
 {
     switch (tex->type())
@@ -994,7 +983,7 @@ static ID3D12Resource* GetTextureGPUResource(const ITexture* tex, int idx, int b
         }
         else
         {
-            descOut = RGBATex2DNoMipViewDesc;
+            descOut = ctx->RGBATex2DFBViewDesc;
             return ctex->m_colorBindTex[bindIdx].Get();
         }
     }
@@ -1131,7 +1120,7 @@ struct D3D12ShaderDataBinding : public GraphicsDataNode<IShaderDataBinding>
                 if (i<m_texs.size() && m_texs[i].tex)
                 {
                     D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
-                    ID3D12Resource* res = GetTextureGPUResource(m_texs[i].tex.get(), b, m_texs[i].idx,
+                    ID3D12Resource* res = GetTextureGPUResource(ctx, m_texs[i].tex.get(), b, m_texs[i].idx,
                                                                 m_texs[i].depth, srvDesc);
                     m_knownViewHandles[b][i] = res;
                     ctx->m_dev->CreateShaderResourceView(res, &srvDesc, handle);
@@ -1178,7 +1167,7 @@ struct D3D12ShaderDataBinding : public GraphicsDataNode<IShaderDataBinding>
                                 heapStart = m_descHeap[b]->GetCPUDescriptorHandleForHeapStart();
                             }
                             m_knownViewHandles[b][i] = res;
-                            ctx->m_dev->CreateShaderResourceView(res, &RGBATex2DNoMipViewDesc,
+                            ctx->m_dev->CreateShaderResourceView(res, &ctx->RGBATex2DFBViewDesc,
                                 CD3DX12_CPU_DESCRIPTOR_HANDLE(heapStart, MAX_UNIFORM_COUNT + i, incSz));
                         }
                     }
@@ -1295,6 +1284,8 @@ struct D3D12CommandQueue : IGraphicsCommandQueue
                                                     nullptr, __uuidof(ID3D12GraphicsCommandList), &m_dynamicCmdList));
     }
 
+    void startRenderer() {}
+
     void stopRenderer()
     {
         m_running = false;
@@ -1491,7 +1482,7 @@ struct D3D12CommandQueue : IGraphicsCommandQueue
             UINT nodeMasks[] = {0,0};
             IUnknown* const queues[] = {m_ctx->m_q.Get(), m_ctx->m_q.Get()};
             m_windowCtx->m_swapChain->ResizeBuffers1(2, m_windowCtx->width, m_windowCtx->height,
-                DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH, nodeMasks, queues);
+                m_ctx->RGBATex2DFBViewDesc.Format, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH, nodeMasks, queues);
             m_windowCtx->m_backBuf = m_windowCtx->m_swapChain->GetCurrentBackBufferIndex();
             m_windowCtx->m_needsResize = false;
         }
@@ -1515,7 +1506,7 @@ struct D3D12CommandQueue : IGraphicsCommandQueue
             };
             m_cmdList->ResourceBarrier(2, msaaSetup);
 
-            m_cmdList->ResolveSubresource(dest.Get(), 0, src, 0, DXGI_FORMAT_R8G8B8A8_UNORM);
+            m_cmdList->ResolveSubresource(dest.Get(), 0, src, 0, m_ctx->RGBATex2DFBViewDesc.Format);
 
             D3D12_RESOURCE_BARRIER msaaTeardown[] =
             {
@@ -1681,7 +1672,7 @@ public:
     : m_parent(parent), m_ctx(ctx)
     {
         D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS qLevels = {};
-        qLevels.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+        qLevels.Format = m_ctx->RGBATex2DFBViewDesc.Format;
         qLevels.SampleCount = m_ctx->m_sampleCount;
         while (SUCCEEDED(ctx->m_dev->CheckFeatureSupport
                          (D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &qLevels, sizeof(qLevels))) &&
diff --git a/lib/graphicsdev/GL.cpp b/lib/graphicsdev/GL.cpp
index a33bf6c..effb1a1 100644
--- a/lib/graphicsdev/GL.cpp
+++ b/lib/graphicsdev/GL.cpp
@@ -18,6 +18,44 @@
 #undef min
 #undef max
 
+static const char* GammaVS =
+"#version 330\n"
+BOO_GLSL_BINDING_HEAD
+"layout(location=0) in vec4 posIn;\n"
+"layout(location=1) in vec4 uvIn;\n"
+"\n"
+"struct VertToFrag\n"
+"{\n"
+"    vec2 uv;\n"
+"};\n"
+"\n"
+"SBINDING(0) out VertToFrag vtf;\n"
+"void main()\n"
+"{\n"
+"    vtf.uv = uvIn.xy;\n"
+"    gl_Position = posIn;\n"
+"}\n";
+
+static const char* GammaFS =
+"#version 330\n"
+BOO_GLSL_BINDING_HEAD
+"struct VertToFrag\n"
+"{\n"
+"    vec2 uv;\n"
+"};\n"
+"\n"
+"SBINDING(0) in VertToFrag vtf;\n"
+"layout(location=0) out vec4 colorOut;\n"
+"TBINDING0 uniform sampler2D screenTex;\n"
+"TBINDING1 uniform sampler2D gammaLUT;\n"
+"void main()\n"
+"{\n"
+"    //int linScale = int(65535.0 * texture(screenTex, vtf.uv).r);\n"
+"    //colorOut = texelFetch(gammaLUT, ivec2(linScale % 256, linScale / 256), 0);\n"
+"    //colorOut = vec4(texture(screenTex, vtf.uv).r, 0.0, 0.0, 1.0);\n"
+"    colorOut = vec4(vtf.uv, 0.0, 1.0);\n"
+"}\n";
+
 namespace boo
 {
 static logvisor::Module Log("boo::GL");
@@ -38,6 +76,42 @@ class GLDataFactoryImpl : public GLDataFactory, public GraphicsDataFactoryHead
     IGraphicsContext* m_parent;
     GLContext* m_glCtx;
     std::unordered_map<uint64_t, std::unique_ptr<GLShareableShader>> m_sharedShaders;
+
+#if 0
+    ObjToken<IShaderPipeline> m_gammaShader;
+    ObjToken<ITextureD> m_gammaLUT;
+    ObjToken<IGraphicsBufferS> m_gammaVBO;
+    ObjToken<IVertexFormat> m_gammaVFMT;
+    void SetupGammaResources()
+    {
+        commitTransaction([this](IGraphicsDataFactory::Context& ctx)
+        {
+            const char* texNames[] = {"screenTex", "gammaLUT"};
+            m_gammaShader = static_cast<Context&>(ctx).newShaderPipeline(GammaVS, GammaFS,
+                2, texNames, 0, nullptr, BlendFactor::One, BlendFactor::Zero,
+                Primitive::TriStrips, ZTest::None, false, true, false, CullMode::None);
+            m_gammaLUT = ctx.newDynamicTexture(256, 256, TextureFormat::I16, TextureClampMode::ClampToEdge);
+            UpdateGammaLUT(m_gammaLUT.get(), 2.2f);
+            const struct Vert {
+                float pos[4];
+                float uv[4];
+            } verts[4] = {
+                {{-1.f, -1.f, 0.f, 1.f}, {0.f, 0.f, 0.f, 0.f}},
+                {{ 1.f, -1.f, 0.f, 1.f}, {1.f, 0.f, 0.f, 0.f}},
+                {{-1.f,  1.f, 0.f, 1.f}, {0.f, 1.f, 0.f, 0.f}},
+                {{ 1.f,  1.f, 0.f, 1.f}, {1.f, 1.f, 0.f, 0.f}}
+            };
+            m_gammaVBO = ctx.newStaticBuffer(BufferUse::Vertex, verts, 32, 4);
+            const VertexElementDescriptor vfmt[] = {
+                {m_gammaVBO.get(), nullptr, VertexSemantic::Position4},
+                {m_gammaVBO.get(), nullptr, VertexSemantic::UV4}
+            };
+            m_gammaVFMT = ctx.newVertexFormat(2, vfmt);
+            return true;
+        });
+    }
+#endif
+
 public:
     GLDataFactoryImpl(IGraphicsContext* parent, GLContext* glCtx)
     : m_parent(parent), m_glCtx(glCtx) {}
@@ -222,6 +296,11 @@ class GLTextureS : public GraphicsDataNode<ITextureS>
             format = GL_RED;
             pxPitch = 1;
             break;
+        case TextureFormat::I16:
+            intFormat = GL_R16;
+            format = GL_RED;
+            pxPitch = 2;
+            break;
         case TextureFormat::DXT1:
             intFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
             compressed = true;
@@ -245,6 +324,7 @@ class GLTextureS : public GraphicsDataNode<ITextureS>
         }
         else
         {
+            //GLenum compType = intFormat == GL_R16 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE;
             for (size_t i=0 ; i<mips ; ++i)
             {
                 glTexImage2D(GL_TEXTURE_2D, i, intFormat, width, height, 0, format, GL_UNSIGNED_BYTE, dataIt);
@@ -299,19 +379,28 @@ class GLTextureSA : public GraphicsDataNode<ITextureSA>
 
         GLenum intFormat, format;
         int pxPitch;
-        if (fmt == TextureFormat::RGBA8)
+        switch (fmt)
         {
+        case TextureFormat::RGBA8:
             intFormat = GL_RGBA8;
             format = GL_RGBA;
             pxPitch = 4;
-        }
-        else if (fmt == TextureFormat::I8)
-        {
+            break;
+        case TextureFormat::I8:
             intFormat = GL_R8;
             format = GL_RED;
             pxPitch = 1;
+            break;
+        case TextureFormat::I16:
+            intFormat = GL_R16;
+            format = GL_RED;
+            pxPitch = 2;
+            break;
+        default:
+            Log.report(logvisor::Fatal, "unsupported tex format");
         }
 
+        //GLenum compType = intFormat == GL_R16 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE;
         for (size_t i=0 ; i<mips ; ++i)
         {
             glTexImage3D(GL_TEXTURE_2D_ARRAY, i, intFormat, width, height, layers, 0, format, GL_UNSIGNED_BYTE, dataIt);
@@ -366,12 +455,18 @@ class GLTextureD : public GraphicsDataNode<ITextureD>
             m_format = GL_RED;
             pxPitch = 1;
             break;
+        case TextureFormat::I16:
+            m_intFormat = GL_R16;
+            m_format = GL_RED;
+            pxPitch = 2;
+            break;
         default:
             Log.report(logvisor::Fatal, "unsupported tex format");
         }
         m_cpuSz = width * height * pxPitch;
         m_cpuBuf.reset(new uint8_t[m_cpuSz]);
 
+        //GLenum compType = m_intFormat == GL_R16 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE;
         glGenTextures(3, m_texs);
         for (int i=0 ; i<3 ; ++i)
         {
@@ -379,6 +474,7 @@ class GLTextureD : public GraphicsDataNode<ITextureD>
             glTexImage2D(GL_TEXTURE_2D, 0, m_intFormat, width, height, 0, m_format, GL_UNSIGNED_BYTE, nullptr);
             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
             SetClampMode(GL_TEXTURE_2D, clampMode);
         }
     }
@@ -392,6 +488,7 @@ public:
         if ((slot & m_validMask) == 0)
         {
             glBindTexture(GL_TEXTURE_2D, m_texs[b]);
+            //GLenum compType = m_intFormat == GL_R16 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE;
             glTexImage2D(GL_TEXTURE_2D, 0, m_intFormat, m_width, m_height, 0, m_format, GL_UNSIGNED_BYTE, m_cpuBuf.get());
             m_validMask |= slot;
         }
@@ -485,6 +582,7 @@ public:
         m_width = width;
         m_height = height;
 
+        //GLenum compType = m_colorFormat == GL_RGBA16 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE;
         if (m_samples > 1)
         {
             glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_texs[0]);
@@ -1048,7 +1146,6 @@ struct GLCommandQueue : IGraphicsCommandQueue
     std::condition_variable m_cv;
     std::mutex m_initmt;
     std::condition_variable m_initcv;
-    std::unique_lock<std::mutex> m_initlk;
     std::thread m_thr;
     
     struct Command
@@ -1217,6 +1314,7 @@ struct GLCommandQueue : IGraphicsCommandQueue
         std::string thrName = std::string(APP->getFriendlyName()) + " GL Rendering Thread";
 #endif
         logvisor::RegisterThreadName(thrName.c_str());
+        GLDataFactoryImpl* dataFactory = static_cast<GLDataFactoryImpl*>(self->m_parent->getDataFactory());
         {
             std::unique_lock<std::mutex> lk(self->m_initmt);
             self->m_parent->makeCurrent();
@@ -1237,6 +1335,8 @@ struct GLCommandQueue : IGraphicsCommandQueue
             glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
             self->m_glCtx->m_sampleCount =
                 flp2(std::min(uint32_t(maxSamples), std::max(uint32_t(1), self->m_glCtx->m_sampleCount)) - 1);
+
+            //dataFactory->SetupGammaResources();
         }
         self->m_initcv.notify_one();
         while (self->m_running)
@@ -1396,10 +1496,45 @@ struct GLCommandQueue : IGraphicsCommandQueue
                 {
                     if (const GLTextureR* tex = cmd.source.cast<GLTextureR>())
                     {
+#if 0
+#ifndef NDEBUG
+                        if (!tex->m_colorBindCount)
+                            Log.report(logvisor::Fatal,
+                                       "texture provided to resolveDisplay() must have at least 1 color binding");
+#endif
+                        glBindFramebuffer(GL_READ_FRAMEBUFFER, tex->m_fbo);
+                        if (tex->m_samples <= 1)
+                        {
+                            glActiveTexture(GL_TEXTURE9);
+                            glBindTexture(GL_TEXTURE_2D, tex->m_bindTexs[0][0]);
+                            glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
+                                                0, 0,
+                                                0, 0,
+                                                tex->m_width, tex->m_height);
+                        }
+                        else
+                        {
+                            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, tex->m_bindFBOs[0][0]);
+                            glBlitFramebuffer(0, 0,
+                                              tex->m_width, tex->m_height,
+                                              0, 0,
+                                              tex->m_width, tex->m_height,
+                                              GL_COLOR_BUFFER_BIT, GL_NEAREST);
+                        }
+
+                        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+                        dataFactory->m_gammaShader.cast<GLShaderPipeline>()->bind();
+                        dataFactory->m_gammaVFMT.cast<GLVertexFormat>()->bind(self->m_drawBuf);
+                        tex->bind(0, 0, false);
+                        dataFactory->m_gammaLUT.cast<GLTextureD>()->bind(1, self->m_drawBuf);
+                        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+#else
                         glBindFramebuffer(GL_READ_FRAMEBUFFER, tex->m_fbo);
                         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
                         glBlitFramebuffer(0, 0, tex->m_width, tex->m_height, 0, 0,
                                           tex->m_width, tex->m_height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+#endif
                     }
                     self->m_parent->present();
                     break;
@@ -1415,12 +1550,14 @@ struct GLCommandQueue : IGraphicsCommandQueue
 
     GLCommandQueue(IGraphicsContext* parent, GLContext* glCtx)
     : m_parent(parent),
-      m_glCtx(glCtx),
-      m_initlk(m_initmt),
-      m_thr(RenderingWorker, this)
+      m_glCtx(glCtx)
+    {}
+
+    void startRenderer()
     {
-        m_initcv.wait(m_initlk);
-        m_initlk.unlock();
+        std::unique_lock<std::mutex> lk(m_initmt);
+        m_thr = std::thread(RenderingWorker, this);
+        m_initcv.wait(lk);
     }
 
     void stopRenderer()
@@ -1660,6 +1797,7 @@ GLTextureR::GLTextureR(const ObjToken<BaseGraphicsData>& parent, GLCommandQueue*
         glGenTextures(depthBindingCount, m_bindTexs[1]);
     }
 
+    //GLenum compType = colorFormat == GL_RGBA16 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE;
     if (samples > 1)
     {
         glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_texs[0]);
diff --git a/lib/graphicsdev/Vulkan.cpp b/lib/graphicsdev/Vulkan.cpp
index 7e6eb36..3993c63 100644
--- a/lib/graphicsdev/Vulkan.cpp
+++ b/lib/graphicsdev/Vulkan.cpp
@@ -2586,6 +2586,8 @@ struct VulkanCommandQueue : IGraphicsCommandQueue
         ThrowIfFailed(vk::CreateFence(m_ctx->m_dev, &fenceInfo, nullptr, &m_dynamicBufFence));
     }
 
+    void startRenderer() {}
+
     void stopRenderer()
     {
         m_running = false;
diff --git a/lib/win/ApplicationWin32.cpp b/lib/win/ApplicationWin32.cpp
index 66890a1..b5ab7c4 100644
--- a/lib/win/ApplicationWin32.cpp
+++ b/lib/win/ApplicationWin32.cpp
@@ -99,6 +99,7 @@ public:
                      std::string_view gfxApi,
                      uint32_t samples,
                      uint32_t anisotropy,
+                     bool deepColor,
                      bool singleInstance)
     : m_callback(callback),
       m_uniqueName(uniqueName),
@@ -109,14 +110,20 @@ public:
     {
         m_3dCtx.m_ctx11.m_sampleCount = samples;
         m_3dCtx.m_ctx11.m_anisotropy = anisotropy;
+        m_3dCtx.m_ctx11.m_fbFormat = deepColor ? DXGI_FORMAT_R16G16B16A16_FLOAT : DXGI_FORMAT_R8G8B8A8_UNORM;
+        //m_3dCtx.m_ctx11.m_fbFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
         m_3dCtx.m_ctx12.m_sampleCount = samples;
         m_3dCtx.m_ctx12.m_anisotropy = anisotropy;
+        m_3dCtx.m_ctx12.RGBATex2DFBViewDesc.Format = deepColor ? DXGI_FORMAT_R16G16B16A16_FLOAT : DXGI_FORMAT_R8G8B8A8_UNORM;
+        //m_3dCtx.m_ctx12.RGBATex2DFBViewDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
         m_3dCtx.m_ctxOgl.m_glCtx.m_sampleCount = samples;
         m_3dCtx.m_ctxOgl.m_glCtx.m_anisotropy = anisotropy;
+        m_3dCtx.m_ctxOgl.m_glCtx.m_deepColor = deepColor;
 #if BOO_HAS_VULKAN
         g_VulkanContext.m_sampleCountColor = samples;
         g_VulkanContext.m_sampleCountDepth = samples;
         g_VulkanContext.m_anisotropy = anisotropy;
+        g_VulkanContext.m_deepColor = deepColor;
 #endif
 
         HMODULE dxgilib = LoadLibraryW(L"dxgi.dll");
@@ -176,6 +183,7 @@ public:
             if (!arg.compare(L"--vulkan"))
             {
                 noD3d = true;
+                useVulkan = true;
             }
             if (!arg.compare(L"--gl"))
             {
@@ -614,7 +622,7 @@ int ApplicationRun(IApplication::EPlatformType platform,
     ATOM a = RegisterClassW(&wndClass);
 
     APP = new ApplicationWin32(cb, uniqueName, friendlyName, pname, args,
-                               gfxApi, samples, anisotropy, singleInstance);
+                               gfxApi, samples, anisotropy, deepColor, singleInstance);
     return APP->run();
 }
 
diff --git a/lib/win/WinCommon.hpp b/lib/win/WinCommon.hpp
index 59e3a03..d66e3c2 100644
--- a/lib/win/WinCommon.hpp
+++ b/lib/win/WinCommon.hpp
@@ -47,6 +47,17 @@ struct D3D12Context
 
     uint32_t m_sampleCount = 1;
     uint32_t m_anisotropy = 1;
+
+    struct RGBATex2DFBViewDesc : D3D12_SHADER_RESOURCE_VIEW_DESC
+    {
+        RGBATex2DFBViewDesc()
+        {
+            Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+            ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
+            Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
+            Texture2D = {UINT(0), UINT(1), UINT(0), 0.0f};
+        }
+    } RGBATex2DFBViewDesc;
 };
 
 struct D3D11Context
@@ -69,6 +80,7 @@ struct D3D11Context
 
     uint32_t m_sampleCount = 1;
     uint32_t m_anisotropy = 1;
+    DXGI_FORMAT m_fbFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
 };
 
 struct Boo3DAppContext
diff --git a/lib/win/WindowWin32.cpp b/lib/win/WindowWin32.cpp
index 181bac4..9e20da5 100644
--- a/lib/win/WindowWin32.cpp
+++ b/lib/win/WindowWin32.cpp
@@ -15,6 +15,10 @@
 #include "boo/graphicsdev/Vulkan.hpp"
 #endif
 
+#if _WIN32_WINNT_WIN10
+#include <dxgi1_5.h>
+#endif
+
 static const int ContextAttribs[] =
 {
     WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
@@ -79,7 +83,6 @@ public:
     {
         /* Create Swap Chain */
         DXGI_SWAP_CHAIN_DESC1 scDesc = {};
-        scDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
         scDesc.SampleDesc.Count = 1;
         scDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
         scDesc.BufferCount = 2;
@@ -96,6 +99,7 @@ public:
             m_dataFactory = _NewD3D12DataFactory(&b3dCtx.m_ctx12, this);
             m_commandQueue = _NewD3D12CommandQueue(&b3dCtx.m_ctx12, &w, this, &cmdQueue);
 
+            scDesc.Format = b3dCtx.m_ctx12.RGBATex2DFBViewDesc.Format;
             scDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
             HRESULT hr = b3dCtx.m_ctx12.m_dxFactory->CreateSwapChainForHwnd(cmdQueue,
                 hwnd, &scDesc, nullptr, nullptr, &m_swapChain);
@@ -117,6 +121,7 @@ public:
         else
 #endif
         {
+            scDesc.Format = b3dCtx.m_ctx11.m_fbFormat;
             if (FAILED(b3dCtx.m_ctx11.m_dxFactory->CreateSwapChainForHwnd(b3dCtx.m_ctx11.m_dev.Get(),
                 hwnd, &scDesc, nullptr, nullptr, &m_swapChain)))
                 Log.report(logvisor::Fatal, "unable to create swap chain");
@@ -257,9 +262,7 @@ public:
                 PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,    //Flags
                 PFD_TYPE_RGBA,            //The kind of framebuffer. RGBA or palette.
                 32,                        //Colordepth of the framebuffer.
-                0, 0, 0, 0, 0, 0,
-                0,
-                0,
+                0, 0, 0, 0, 0, 0, 0, 0,
                 0,
                 0, 0, 0, 0,
                 24,                        //Number of bits for the depthbuffer
@@ -272,8 +275,46 @@ public:
 
             int pf = ChoosePixelFormat(w.m_deviceContext, &pfd);
             SetPixelFormat(w.m_deviceContext, pf, &pfd);
+
+#if 0
+            HGLRC tmpCtx = wglCreateContext(w.m_deviceContext);
+            wglMakeCurrent(w.m_deviceContext, tmpCtx);
+            wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)
+                wglGetProcAddress("wglCreateContextAttribsARB");
+            wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)
+                wglGetProcAddress("wglChoosePixelFormatARB");
+            wglMakeCurrent(w.m_deviceContext, 0);
+            wglDeleteContext(tmpCtx);
+
+            if (b3dCtx.m_ctxOgl.m_glCtx.m_deepColor)
+            {
+                const int attribs1[] =
+                {
+                    WGL_SUPPORT_OPENGL_ARB, TRUE,
+                    WGL_DRAW_TO_WINDOW_ARB, TRUE,
+                    WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
+                    WGL_RED_BITS_ARB, 10,
+                    WGL_GREEN_BITS_ARB, 10,
+                    WGL_BLUE_BITS_ARB, 10,
+                    WGL_ALPHA_BITS_ARB, 2,
+                    WGL_DOUBLE_BUFFER_ARB, TRUE,
+                    0, // zero terminates the list
+                };
+                float fattribs[] = {
+                    0.0f, // zero terminates the list
+                };
+
+                int pixelFormat;
+                UINT numFormats;
+
+                wglChoosePixelFormatARB(w.m_deviceContext, attribs1, fattribs, 1, &pixelFormat, &numFormats);
+                if (numFormats)
+                    SetPixelFormat(w.m_deviceContext, pixelFormat, nullptr);
+            }
+#endif
         }
 
+        //w.m_mainContext = wglCreateContextAttribsARB(w.m_deviceContext, 0, ContextAttribs);
         w.m_mainContext = wglCreateContext(w.m_deviceContext);
         if (!w.m_mainContext)
             Log.report(logvisor::Fatal, "unable to create window's main context");
@@ -284,6 +325,7 @@ public:
 
         m_dataFactory = _NewGLDataFactory(this, &b3dCtx.m_ctxOgl.m_glCtx);
         m_commandQueue = _NewGLCommandQueue(this, &b3dCtx.m_ctxOgl.m_glCtx);
+        m_commandQueue->startRenderer();
     }
 
     ~GraphicsContextWin32GL()
@@ -565,14 +607,29 @@ public:
          * supported format will be returned. */
         if (formatCount >= 1)
         {
-            for (int i=0 ; i<formatCount ; ++i)
+            if (m_ctx->m_deepColor)
             {
-                if (surfFormats[i].format == VK_FORMAT_B8G8R8A8_UNORM ||
-                    surfFormats[i].format == VK_FORMAT_R8G8B8A8_UNORM)
+                for (int i=0 ; i<formatCount ; ++i)
                 {
-                    m_format = surfFormats[i].format;
-                    m_colorspace = surfFormats[i].colorSpace;
-                    break;
+                    if (surfFormats[i].format == VK_FORMAT_R16G16B16A16_UNORM)
+                    {
+                        m_format = surfFormats[i].format;
+                        m_colorspace = surfFormats[i].colorSpace;
+                        break;
+                    }
+                }
+            }
+            if (m_format == VK_FORMAT_UNDEFINED)
+            {
+                for (int i=0 ; i<formatCount ; ++i)
+                {
+                    if (surfFormats[i].format == VK_FORMAT_B8G8R8A8_UNORM ||
+                        surfFormats[i].format == VK_FORMAT_R8G8B8A8_UNORM)
+                    {
+                        m_format = surfFormats[i].format;
+                        m_colorspace = surfFormats[i].colorSpace;
+                        break;
+                    }
                 }
             }
         }
diff --git a/test/main.cpp b/test/main.cpp
index b87674b..b0f0b1c 100644
--- a/test/main.cpp
+++ b/test/main.cpp
@@ -294,7 +294,7 @@ struct TestApplicationCallback : IApplicationCallback
             /* Create render target */
             int x, y, w, h;
             self->mainWindow->getWindowFrame(x, y, w, h);
-            self->m_renderTarget = ctx.newRenderTexture(w, h, boo::TextureClampMode::Repeat, 0, 0);
+            self->m_renderTarget = ctx.newRenderTexture(w, h, boo::TextureClampMode::Repeat, 1, 0);
 
             /* Make Tri-strip VBO */
             struct Vert
@@ -439,7 +439,8 @@ struct TestApplicationCallback : IApplicationCallback
                     "struct VertToFrag {float4 out_pos : SV_Position; float2 out_uv : UV;};\n"
                     "float4 main(in VertToFrag d) : SV_Target0\n"
                     "{\n"
-                    "    return tex.Sample(samp, d.out_uv);\n"
+                    "    //return tex.Sample(samp, d.out_uv);\n"
+                    "    return float4(d.out_uv.xy, 0.0, 1.0);\n"
                     "}\n";
 
                 pipeline = d3dF.newShaderPipeline(VS, PS, nullptr, nullptr, nullptr, vfmt,