summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorTim Foley <tfoleyNV@users.noreply.github.com>2018-08-06 15:52:38 -0700
committerGitHub <noreply@github.com>2018-08-06 15:52:38 -0700
commit73ff6907d723003d30e400f661876e7960de574f (patch)
tree76fb87e0d7cdf6310c4a62753556dbf061842d7b /tools
parent68d705f6c805c9b4d31b386e065762e6db13ad18 (diff)
Add basic support for "Dear IMGUI" (#625)
This isn't being made visible just yet, but it will allow us to have a simple UI for loading models into the model-viewer example. In order to support rendering with IMGUI I had to add the following to the `Renderer` layer: * viewports * scissor rects * blend support These are really only fully implemented for D3D11, but adding them to the other back-ends should be a reasonably small task.
Diffstat (limited to 'tools')
-rw-r--r--tools/gfx/d3d-util.cpp1
-rw-r--r--tools/gfx/gfx.vcxproj10
-rw-r--r--tools/gfx/gfx.vcxproj.filters6
-rw-r--r--tools/gfx/gui.cpp398
-rw-r--r--tools/gfx/gui.h28
-rw-r--r--tools/gfx/render-d3d11.cpp193
-rw-r--r--tools/gfx/render-d3d12.cpp44
-rw-r--r--tools/gfx/render-gl.cpp42
-rw-r--r--tools/gfx/render-vk.cpp46
-rw-r--r--tools/gfx/render.cpp1
-rw-r--r--tools/gfx/render.h106
-rw-r--r--tools/gfx/window.cpp33
12 files changed, 904 insertions, 4 deletions
diff --git a/tools/gfx/d3d-util.cpp b/tools/gfx/d3d-util.cpp
index 19135707b..f479af186 100644
--- a/tools/gfx/d3d-util.cpp
+++ b/tools/gfx/d3d-util.cpp
@@ -31,6 +31,7 @@ using namespace Slang;
case Format::RG_Float32: return DXGI_FORMAT_R32G32_FLOAT;
case Format::R_Float32: return DXGI_FORMAT_R32_FLOAT;
case Format::RGBA_Unorm_UInt8: return DXGI_FORMAT_R8G8B8A8_UNORM;
+ case Format::R_UInt16: return DXGI_FORMAT_R16_UINT;
case Format::R_UInt32: return DXGI_FORMAT_R32_UINT;
case Format::D_Float32: return DXGI_FORMAT_D32_FLOAT;
diff --git a/tools/gfx/gfx.vcxproj b/tools/gfx/gfx.vcxproj
index cbafe84b1..6de379c73 100644
--- a/tools/gfx/gfx.vcxproj
+++ b/tools/gfx/gfx.vcxproj
@@ -95,7 +95,7 @@
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>..\..;..\..\external;..\..\source;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>..\..;..\..\external;..\..\source;..\..\external\imgui;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<Optimization>Disabled</Optimization>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
@@ -113,7 +113,7 @@
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>..\..;..\..\external;..\..\source;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>..\..;..\..\external;..\..\source;..\..\external\imgui;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<Optimization>Disabled</Optimization>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
@@ -131,7 +131,7 @@
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>..\..;..\..\external;..\..\source;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>..\..;..\..\external;..\..\source;..\..\external\imgui;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<Optimization>Full</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
@@ -153,7 +153,7 @@
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>..\..;..\..\external;..\..\source;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>..\..;..\..\external;..\..\source;..\..\external\imgui;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<Optimization>Full</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
@@ -174,6 +174,7 @@
<ClInclude Include="circular-resource-heap-d3d12.h" />
<ClInclude Include="d3d-util.h" />
<ClInclude Include="descriptor-heap-d3d12.h" />
+ <ClInclude Include="gui.h" />
<ClInclude Include="model.h" />
<ClInclude Include="render-d3d11.h" />
<ClInclude Include="render-d3d12.h" />
@@ -194,6 +195,7 @@
<ClCompile Include="circular-resource-heap-d3d12.cpp" />
<ClCompile Include="d3d-util.cpp" />
<ClCompile Include="descriptor-heap-d3d12.cpp" />
+ <ClCompile Include="gui.cpp" />
<ClCompile Include="model.cpp" />
<ClCompile Include="render-d3d11.cpp" />
<ClCompile Include="render-d3d12.cpp" />
diff --git a/tools/gfx/gfx.vcxproj.filters b/tools/gfx/gfx.vcxproj.filters
index f1c7f7f5e..8164d45b0 100644
--- a/tools/gfx/gfx.vcxproj.filters
+++ b/tools/gfx/gfx.vcxproj.filters
@@ -18,6 +18,9 @@
<ClInclude Include="descriptor-heap-d3d12.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="gui.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
<ClInclude Include="model.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -74,6 +77,9 @@
<ClCompile Include="descriptor-heap-d3d12.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="gui.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="model.cpp">
<Filter>Source Files</Filter>
</ClCompile>
diff --git a/tools/gfx/gui.cpp b/tools/gfx/gui.cpp
new file mode 100644
index 000000000..85a080526
--- /dev/null
+++ b/tools/gfx/gui.cpp
@@ -0,0 +1,398 @@
+// gui.cpp
+#include "gui.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#include "external/imgui/examples/imgui_impl_win32.h"
+IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+#endif
+
+
+namespace gfx {
+
+#ifdef _WIN32
+LRESULT CALLBACK guiWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ return ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam);
+}
+void setNativeWindowHook(Window* window, WNDPROC proc);
+#endif
+
+
+GUI::GUI(Window* window, Renderer* inRenderer)
+ : renderer(inRenderer)
+{
+ ImGui::CreateContext();
+ ImGuiIO& io = ImGui::GetIO();
+
+#ifdef _WIN32
+ ImGui_ImplWin32_Init(getPlatformWindowHandle(window));
+
+ setNativeWindowHook(window, &guiWindowProc);
+#endif
+
+ // Let's do the initialization work required for our graphics API
+ // abstraction layer, so that we can pipe all IMGUI rendering
+ // through the same interface as other work.
+ //
+
+ static const char* shaderCode =
+ "cbuffer U { float4x4 mvp; }; \
+ Texture2D t; \
+ SamplerState s; \
+ struct AssembledVertex { \
+ float2 pos; \
+ float2 uv; \
+ float4 col; \
+ }; \
+ struct CoarseVertex { \
+ float4 col; \
+ float2 uv; \
+ }; \
+ struct VSOutput { \
+ CoarseVertex cv : U; \
+ float4 pos : SV_Position; \
+ }; \
+ void vertexMain( \
+ AssembledVertex i : U, \
+ out VSOutput o) \
+ { \
+ o.cv.col = i.col; \
+ o.cv.uv = i.uv; \
+ o.pos = mul(mvp, \
+ float4(i.pos.xy, 0.f, 1.f)); \
+ } \
+ float4 fragmentMain( \
+ CoarseVertex i : U) \
+ : SV_target \
+ { \
+ return i.col * t.Sample(s, i.uv); \
+ } \
+ ";
+
+ SlangSession* slangSession = spCreateSession(nullptr);
+ SlangCompileRequest* slangRequest = spCreateCompileRequest(slangSession);
+
+ // TODO: These two lines need to change based on what the target graphics API
+ // is, so we need a way for a `Renderer` to pass back its prefeerred code
+ // format and profile name...
+ //
+ int targetIndex = spAddCodeGenTarget(slangRequest, SLANG_DXBC);
+ spSetTargetProfile(slangRequest, targetIndex, spFindProfile(slangSession, "sm_4_0"));
+
+ int translationUnitIndex = spAddTranslationUnit(slangRequest, SLANG_SOURCE_LANGUAGE_SLANG, nullptr);
+ spAddTranslationUnitSourceString(slangRequest, translationUnitIndex, "gui.cpp.slang", shaderCode);
+
+ char const* vertexEntryPointName = "vertexMain";
+ char const* fragmentEntryPointName = "fragmentMain";
+ int vertexIndex = spAddEntryPoint(slangRequest, translationUnitIndex, vertexEntryPointName, SLANG_STAGE_VERTEX);
+ int fragmentIndex = spAddEntryPoint(slangRequest, translationUnitIndex, fragmentEntryPointName, SLANG_STAGE_FRAGMENT);
+
+ const SlangResult compileRes = spCompile(slangRequest);
+ if(auto diagnostics = spGetDiagnosticOutput(slangRequest))
+ {
+ reportError("%s", diagnostics);
+ }
+ if(SLANG_FAILED(compileRes))
+ {
+ spDestroyCompileRequest(slangRequest);
+ spDestroySession(slangSession);
+ assert(!"unexpected");
+ return;
+ }
+
+ ISlangBlob* vertexShaderBlob = nullptr;
+ spGetEntryPointCodeBlob(slangRequest, vertexIndex, 0, &vertexShaderBlob);
+
+ ISlangBlob* fragmentShaderBlob = nullptr;
+ spGetEntryPointCodeBlob(slangRequest, fragmentIndex, 0, &fragmentShaderBlob);
+
+ char const* vertexCode = (char const*) vertexShaderBlob->getBufferPointer();
+ char const* vertexCodeEnd = vertexCode + vertexShaderBlob->getBufferSize();
+
+ char const* fragmentCode = (char const*) fragmentShaderBlob->getBufferPointer();
+ char const* fragmentCodeEnd = fragmentCode + fragmentShaderBlob->getBufferSize();
+
+ spDestroyCompileRequest(slangRequest);
+ spDestroySession(slangSession);
+
+ gfx::ShaderProgram::KernelDesc kernelDescs[] =
+ {
+ { gfx::StageType::Vertex, vertexCode, vertexCodeEnd },
+ { gfx::StageType::Fragment, fragmentCode, fragmentCodeEnd },
+ };
+
+ gfx::ShaderProgram::Desc programDesc;
+ programDesc.pipelineType = gfx::PipelineType::Graphics;
+ programDesc.kernels = &kernelDescs[0];
+ programDesc.kernelCount = 2;
+
+ auto program = renderer->createProgram(programDesc);
+
+ vertexShaderBlob->release();
+ fragmentShaderBlob->release();
+
+ InputElementDesc inputElements[] = {
+ {"U", 0, Format::RG_Float32, offsetof(ImDrawVert, pos) },
+ {"U", 1, Format::RG_Float32, offsetof(ImDrawVert, uv) },
+ {"U", 2, Format::RGBA_Unorm_UInt8, offsetof(ImDrawVert, col) },
+ };
+ auto inputLayout = renderer->createInputLayout(
+ &inputElements[0],
+ SLANG_COUNT_OF(inputElements));
+
+ //
+
+ List<DescriptorSetLayout::SlotRangeDesc> descriptorSetRanges;
+ descriptorSetRanges.Add(DescriptorSetLayout::SlotRangeDesc(DescriptorSlotType::UniformBuffer));
+ descriptorSetRanges.Add(DescriptorSetLayout::SlotRangeDesc(DescriptorSlotType::SampledImage));
+ descriptorSetRanges.Add(DescriptorSetLayout::SlotRangeDesc(DescriptorSlotType::Sampler));
+
+ DescriptorSetLayout::Desc descriptorSetLayoutDesc;
+ descriptorSetLayoutDesc.slotRangeCount = descriptorSetRanges.Count();
+ descriptorSetLayoutDesc.slotRanges = descriptorSetRanges.Buffer();
+
+ descriptorSetLayout = renderer->createDescriptorSetLayout(descriptorSetLayoutDesc);
+
+ List<PipelineLayout::DescriptorSetDesc> pipelineDescriptorSets;
+ pipelineDescriptorSets.Add(PipelineLayout::DescriptorSetDesc(descriptorSetLayout));
+
+ PipelineLayout::Desc pipelineLayoutDesc;
+ pipelineLayoutDesc.descriptorSetCount = pipelineDescriptorSets.Count();
+ pipelineLayoutDesc.descriptorSets = pipelineDescriptorSets.Buffer();
+ pipelineLayoutDesc.renderTargetCount = 1;
+
+ pipelineLayout = renderer->createPipelineLayout(pipelineLayoutDesc);
+
+ TargetBlendDesc targetBlendDesc;
+ targetBlendDesc.color.srcFactor = BlendFactor::SrcAlpha;
+ targetBlendDesc.color.dstFactor = BlendFactor::InvSrcAlpha;
+ targetBlendDesc.alpha.srcFactor = BlendFactor::InvSrcAlpha;
+ targetBlendDesc.alpha.dstFactor = BlendFactor::Zero;
+
+ GraphicsPipelineStateDesc pipelineDesc;
+ pipelineDesc.renderTargetCount = 1;
+ pipelineDesc.program = program;
+ pipelineDesc.pipelineLayout = pipelineLayout;
+ pipelineDesc.inputLayout = inputLayout;
+ pipelineDesc.blend.targets = &targetBlendDesc;
+ pipelineDesc.blend.targetCount = 1;
+ pipelineDesc.rasterizer.cullMode = CullMode::None;
+
+ // Set up the pieces of fixed-function state that we care about
+ pipelineDesc.depthStencil.depthTestEnable = false;
+
+ // TODO: need to set up blending state...
+
+ pipelineState = renderer->createGraphicsPipelineState(pipelineDesc);
+
+ // Initialize the texture atlas
+ unsigned char* pixels;
+ int width, height;
+ io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
+
+ {
+ gfx::TextureResource::Desc desc;
+ desc.init2D(Resource::Type::Texture2D, Format::RGBA_Unorm_UInt8, width, height, 1);
+ desc.setDefaults(Resource::Usage::PixelShaderResource);
+
+
+ ptrdiff_t mipRowStrides[] = { ptrdiff_t(width * 4 * sizeof(unsigned char)) };
+ void* subResourceData[] = { pixels };
+ TextureResource::Data initData;
+ initData.mipRowStrides = mipRowStrides;
+ initData.numMips = 1;
+ initData.numSubResources = 1;
+ initData.subResources = subResourceData;
+
+ auto texture = renderer->createTextureResource(Resource::Usage::PixelShaderResource, desc, &initData);
+
+ gfx::ResourceView::Desc viewDesc;
+ viewDesc.format = desc.format;
+ viewDesc.type = ResourceView::Type::ShaderResource;
+ auto textureView = renderer->createTextureView(texture, viewDesc);
+
+ io.Fonts->TexID = (void*) textureView.detach();
+ }
+
+ {
+ SamplerState::Desc desc;
+ samplerState = renderer->createSamplerState(desc);
+ }
+}
+
+
+
+void GUI::beginFrame()
+{
+#ifdef _WIN32
+ ImGui_ImplWin32_NewFrame();
+#endif
+ ImGui::NewFrame();
+}
+
+void GUI::endFrame()
+{
+ ImGui::Render();
+
+ ImDrawData* draw_data = ImGui::GetDrawData();
+ auto vertexCount = draw_data->TotalVtxCount;
+ auto indexCount = draw_data->TotalIdxCount;
+ int commandListCount = draw_data->CmdListsCount;
+
+ if(!vertexCount) return;
+ if(!indexCount) return;
+ if(!commandListCount) return;
+
+ // Allocate transient vertex/index buffers to hold the data for this frame.
+
+ gfx::BufferResource::Desc vertexBufferDesc;
+ vertexBufferDesc.init(vertexCount * sizeof(ImDrawVert));
+ vertexBufferDesc.setDefaults(Resource::Usage::VertexBuffer);
+ vertexBufferDesc.cpuAccessFlags = Resource::AccessFlag::Write;
+ auto vertexBuffer = renderer->createBufferResource(
+ Resource::Usage::VertexBuffer,
+ vertexBufferDesc);
+
+ gfx::BufferResource::Desc indexBufferDesc;
+ indexBufferDesc.init(indexCount * sizeof(ImDrawIdx));
+ indexBufferDesc.setDefaults(Resource::Usage::IndexBuffer);
+ indexBufferDesc.cpuAccessFlags = Resource::AccessFlag::Write;
+ auto indexBuffer = renderer->createBufferResource(
+ Resource::Usage::IndexBuffer,
+ indexBufferDesc);
+
+ {
+ ImDrawVert* dstVertex = (ImDrawVert*) renderer->map(vertexBuffer, MapFlavor::WriteDiscard);
+ ImDrawIdx* dstIndex = (ImDrawIdx*) renderer->map(indexBuffer, MapFlavor::WriteDiscard);
+
+ for(int ii = 0; ii < commandListCount; ++ii)
+ {
+ const ImDrawList* commandList = draw_data->CmdLists[ii];
+ memcpy(dstVertex, commandList->VtxBuffer.Data, commandList->VtxBuffer.Size * sizeof(ImDrawVert));
+ memcpy(dstIndex, commandList->IdxBuffer.Data, commandList->IdxBuffer.Size * sizeof(ImDrawIdx));
+ dstVertex += commandList->VtxBuffer.Size;
+ dstIndex += commandList->IdxBuffer.Size;
+ }
+
+ renderer->unmap(vertexBuffer);
+ renderer->unmap(indexBuffer);
+ }
+
+ // Allocate a transient constant buffer for projection matrix
+ gfx::BufferResource::Desc constantBufferDesc;
+ constantBufferDesc.init(sizeof(glm::mat4x4));
+ constantBufferDesc.setDefaults(Resource::Usage::ConstantBuffer);
+ constantBufferDesc.cpuAccessFlags = Resource::AccessFlag::Write;
+ auto constantBuffer = renderer->createBufferResource(
+ Resource::Usage::ConstantBuffer,
+ constantBufferDesc);
+
+ {
+ glm::mat4x4* dstMVP = (glm::mat4x4*) renderer->map(constantBuffer, MapFlavor::WriteDiscard);
+
+ float L = draw_data->DisplayPos.x;
+ float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
+ float T = draw_data->DisplayPos.y;
+ float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
+ float mvp[4][4] =
+ {
+ { 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
+ { 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
+ { 0.0f, 0.0f, 0.5f, 0.0f },
+ { (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
+ };
+ memcpy(dstMVP, mvp, sizeof(mvp));
+
+ renderer->unmap(constantBuffer);
+ }
+
+ gfx::Viewport viewport;
+ viewport.originX = 0;
+ viewport.originY = 0;
+ viewport.extentY = draw_data->DisplaySize.y;
+ viewport.extentX = draw_data->DisplaySize.x;
+ viewport.extentY = draw_data->DisplaySize.y;
+ viewport.minZ = 0;
+ viewport.maxZ = 0;
+
+ renderer->setViewport(viewport);
+
+ auto pipelineType = PipelineType::Graphics;
+ renderer->setPipelineState(pipelineType, pipelineState);
+
+ renderer->setVertexBuffer(0, vertexBuffer, sizeof(ImDrawVert));
+ renderer->setIndexBuffer(indexBuffer, sizeof(ImDrawIdx) == 2 ? Format::R_UInt16 : Format::R_UInt32);
+ renderer->setPrimitiveTopology(PrimitiveTopology::TriangleList);
+
+ UInt vertexOffset = 0;
+ UInt indexOffset = 0;
+ ImVec2 pos = draw_data->DisplayPos;
+ for(int ii = 0; ii < commandListCount; ++ii)
+ {
+ auto commandList = draw_data->CmdLists[ii];
+ auto commandCount = commandList->CmdBuffer.Size;
+ for(int jj = 0; jj < commandCount; jj++)
+ {
+ auto command = &commandList->CmdBuffer[jj];
+ if(auto userCallback = command->UserCallback)
+ {
+ userCallback(commandList, command);
+ }
+ else
+ {
+ ScissorRect rect =
+ {
+ (Int)(command->ClipRect.x - pos.x),
+ (Int)(command->ClipRect.y - pos.y),
+ (Int)(command->ClipRect.z - pos.x),
+ (Int)(command->ClipRect.w - pos.y)
+ };
+ renderer->setScissorRect(rect);
+
+ // TODO: This should be a dynamic/transient descriptor set...
+ auto descriptorSet = renderer->createDescriptorSet(descriptorSetLayout);
+ descriptorSet->setConstantBuffer(0, 0, constantBuffer);
+ descriptorSet->setResource(1, 0,
+ (gfx::ResourceView*) command->TextureId);
+ descriptorSet->setSampler(2, 0,
+ samplerState);
+
+ renderer->setDescriptorSet(
+ pipelineType,
+ pipelineLayout,
+ 0,
+ descriptorSet);
+
+ renderer->drawIndexed(command->ElemCount, indexOffset, vertexOffset);
+ }
+ indexOffset += command->ElemCount;
+ }
+ vertexOffset += commandList->VtxBuffer.Size;
+ }
+}
+
+GUI::~GUI()
+{
+ auto& io = ImGui::GetIO();
+
+ {
+ RefPtr<ResourceView> textureView;
+ textureView.attach((ResourceView*) io.Fonts->TexID);
+ textureView = nullptr;
+ }
+
+#ifdef _WIN32
+ ImGui_ImplWin32_Shutdown();
+#endif
+
+ ImGui::DestroyContext();
+}
+
+} // gfx
+
+#include "external/imgui/imgui.cpp"
+#include "external/imgui/imgui_draw.cpp"
+#ifdef _WIN32
+#include "external/imgui/examples/imgui_impl_win32.cpp"
+#endif
diff --git a/tools/gfx/gui.h b/tools/gfx/gui.h
new file mode 100644
index 000000000..cbec5796f
--- /dev/null
+++ b/tools/gfx/gui.h
@@ -0,0 +1,28 @@
+// gui.h
+#pragma once
+
+#include "render.h"
+#include "vector-math.h"
+#include "window.h"
+
+#include "external/imgui/imgui.h"
+
+namespace gfx {
+
+struct GUI : RefObject
+{
+ GUI(Window* window, Renderer* renderer);
+ ~GUI();
+
+ void beginFrame();
+ void endFrame();
+
+private:
+ RefPtr<Renderer> renderer;
+ RefPtr<PipelineState> pipelineState;
+ RefPtr<DescriptorSetLayout> descriptorSetLayout;
+ RefPtr<PipelineLayout> pipelineLayout;
+ RefPtr<SamplerState> samplerState;
+};
+
+} // gfx
diff --git a/tools/gfx/render-d3d11.cpp b/tools/gfx/render-d3d11.cpp
index 57c0672bd..7bf712216 100644
--- a/tools/gfx/render-d3d11.cpp
+++ b/tools/gfx/render-d3d11.cpp
@@ -86,6 +86,8 @@ public:
virtual void setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets) override;
virtual void setIndexBuffer(BufferResource* buffer, Format indexFormat, UInt offset) override;
virtual void setDepthStencilTarget(ResourceView* depthStencilView) override;
+ void setViewports(UInt count, Viewport const* viewports) override;
+ void setScissorRects(UInt count, ScissorRect const* rects) override;
virtual void setPipelineState(PipelineType pipelineType, PipelineState* state) override;
virtual void draw(UInt vertexCount, UInt startVertex) override;
virtual void drawIndexed(UInt indexCount, UInt startIndex, UInt baseVertex) override;
@@ -282,8 +284,11 @@ public:
RefPtr<InputLayoutImpl> m_inputLayout;
ComPtr<ID3D11DepthStencilState> m_depthStencilState;
ComPtr<ID3D11RasterizerState> m_rasterizerState;
+ ComPtr<ID3D11BlendState> m_blendState;
UINT m_stencilRef;
+ float m_blendColor[4];
+ UINT m_sampleMask;
};
class ComputePipelineStateImpl : public PipelineStateImpl
@@ -1111,6 +1116,7 @@ Result D3D11Renderer::createInputLayout(const InputElementDesc* inputElementsIn,
switch (inputElementsIn[ii].format)
{
case Format::RGBA_Float32:
+ case Format::RGBA_Unorm_UInt8:
typeName = "float4";
break;
case Format::RGB_Float32:
@@ -1245,6 +1251,49 @@ void D3D11Renderer::setDepthStencilTarget(ResourceView* depthStencilView)
m_targetBindingsDirty[int(PipelineType::Graphics)] = true;
}
+void D3D11Renderer::setViewports(UInt count, Viewport const* viewports)
+{
+ static const int kMaxViewports = D3D11_VIEWPORT_AND_SCISSORRECT_MAX_INDEX + 1;
+ assert(count <= kMaxViewports);
+
+ D3D11_VIEWPORT dxViewports[kMaxViewports];
+ for(UInt ii = 0; ii < count; ++ii)
+ {
+ auto& inViewport = viewports[ii];
+ auto& dxViewport = dxViewports[ii];
+
+ dxViewport.TopLeftX = inViewport.originX;
+ dxViewport.TopLeftY = inViewport.originY;
+ dxViewport.Width = inViewport.extentX;
+ dxViewport.Height = inViewport.extentY;
+ dxViewport.MinDepth = inViewport.minZ;
+ dxViewport.MaxDepth = inViewport.maxZ;
+ }
+
+ m_immediateContext->RSSetViewports(count, dxViewports);
+}
+
+void D3D11Renderer::setScissorRects(UInt count, ScissorRect const* rects)
+{
+ static const int kMaxScissorRects = D3D11_VIEWPORT_AND_SCISSORRECT_MAX_INDEX + 1;
+ assert(count <= kMaxScissorRects);
+
+ D3D11_RECT dxRects[kMaxScissorRects];
+ for(UInt ii = 0; ii < count; ++ii)
+ {
+ auto& inRect = rects[ii];
+ auto& dxRect = dxRects[ii];
+
+ dxRect.left = inRect.minX;
+ dxRect.top = inRect.minY;
+ dxRect.right = inRect.maxX;
+ dxRect.bottom = inRect.maxY;
+ }
+
+ m_immediateContext->RSSetScissorRects(count, dxRects);
+}
+
+
void D3D11Renderer::setPipelineState(PipelineType pipelineType, PipelineState* state)
{
switch(pipelineType)
@@ -1288,6 +1337,7 @@ void D3D11Renderer::setPipelineState(PipelineType pipelineType, PipelineState* s
// OM
+ m_immediateContext->OMSetBlendState(stateImpl->m_blendState, stateImpl->m_blendColor, stateImpl->m_sampleMask);
m_immediateContext->OMSetDepthStencilState(stateImpl->m_depthStencilState, stateImpl->m_stencilRef);
m_currentGraphicsState = stateImpl;
@@ -1409,6 +1459,82 @@ static D3D11_CULL_MODE translateCullMode(CullMode mode)
}
}
+bool isBlendDisabled(AspectBlendDesc const& desc)
+{
+ return desc.op == BlendOp::Add
+ && desc.srcFactor == BlendFactor::One
+ && desc.dstFactor == BlendFactor::Zero;
+}
+
+
+bool isBlendDisabled(TargetBlendDesc const& desc)
+{
+ return isBlendDisabled(desc.color)
+ && isBlendDisabled(desc.alpha);
+}
+
+D3D11_BLEND_OP translateBlendOp(BlendOp op)
+{
+ switch(op)
+ {
+ default:
+ assert(!"unimplemented");
+ return (D3D11_BLEND_OP) -1;
+
+#define CASE(FROM, TO) case BlendOp::FROM: return D3D11_BLEND_OP_##TO
+ CASE(Add, ADD);
+ CASE(Subtract, SUBTRACT);
+ CASE(ReverseSubtract, REV_SUBTRACT);
+ CASE(Min, MIN);
+ CASE(Max, MAX);
+#undef CASE
+ }
+}
+
+D3D11_BLEND translateBlendFactor(BlendFactor factor)
+{
+ switch(factor)
+ {
+ default:
+ assert(!"unimplemented");
+ return (D3D11_BLEND) -1;
+
+#define CASE(FROM, TO) case BlendFactor::FROM: return D3D11_BLEND_##TO
+ CASE(Zero, ZERO);
+ CASE(One, ONE);
+ CASE(SrcColor, SRC_COLOR);
+ CASE(InvSrcColor, INV_SRC_COLOR);
+ CASE(SrcAlpha, SRC_ALPHA);
+ CASE(InvSrcAlpha, INV_SRC_ALPHA);
+ CASE(DestAlpha, DEST_ALPHA);
+ CASE(InvDestAlpha, INV_DEST_ALPHA);
+ CASE(DestColor, DEST_COLOR);
+ CASE(InvDestColor, INV_DEST_ALPHA);
+ CASE(SrcAlphaSaturate, SRC_ALPHA_SAT);
+ CASE(BlendColor, BLEND_FACTOR);
+ CASE(InvBlendColor, INV_BLEND_FACTOR);
+ CASE(SecondarySrcColor, SRC1_COLOR);
+ CASE(InvSecondarySrcColor, INV_SRC1_COLOR);
+ CASE(SecondarySrcAlpha, SRC1_ALPHA);
+ CASE(InvSecondarySrcAlpha, INV_SRC1_ALPHA);
+#undef CASE
+ }
+}
+
+D3D11_COLOR_WRITE_ENABLE translateRenderTargetWriteMask(RenderTargetWriteMaskT mask)
+{
+ UINT result = 0;
+#define CASE(FROM, TO) if(mask & RenderTargetWriteMask::Enable##FROM) result |= D3D11_COLOR_WRITE_ENABLE_##TO
+
+ CASE(Red, RED);
+ CASE(Green, GREEN);
+ CASE(Blue, BLUE);
+ CASE(Alpha, ALPHA);
+
+#undef CASE
+ return D3D11_COLOR_WRITE_ENABLE(result);
+}
+
Result D3D11Renderer::createGraphicsPipelineState(const GraphicsPipelineStateDesc& desc, PipelineState** outState)
{
auto programImpl = (ShaderProgramImpl*) desc.program;
@@ -1458,14 +1584,81 @@ Result D3D11Renderer::createGraphicsPipelineState(const GraphicsPipelineStateDes
}
+ ComPtr<ID3D11BlendState> blendState;
+ {
+ auto& srcDesc = desc.blend;
+ D3D11_BLEND_DESC dstDesc = {};
+
+ TargetBlendDesc defaultTargetBlendDesc;
+
+ static const UInt kMaxTargets = D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT;
+ if(srcDesc.targetCount > kMaxTargets) return SLANG_FAIL;
+
+ for(UInt ii = 0; ii < kMaxTargets; ++ii)
+ {
+ TargetBlendDesc const* srcTargetBlendDescPtr = nullptr;
+ if(ii < srcDesc.targetCount)
+ {
+ srcTargetBlendDescPtr = &srcDesc.targets[ii];
+ }
+ else if(srcDesc.targetCount == 0)
+ {
+ srcTargetBlendDescPtr = &defaultTargetBlendDesc;
+ }
+ else
+ {
+ srcTargetBlendDescPtr = &srcDesc.targets[srcDesc.targetCount-1];
+ }
+
+ auto& srcTargetBlendDesc = *srcTargetBlendDescPtr;
+ auto& dstTargetBlendDesc = dstDesc.RenderTarget[ii];
+
+ if(isBlendDisabled(srcTargetBlendDesc))
+ {
+ dstTargetBlendDesc.BlendEnable = false;
+ dstTargetBlendDesc.BlendOp = D3D11_BLEND_OP_ADD;
+ dstTargetBlendDesc.BlendOpAlpha = D3D11_BLEND_OP_ADD;
+ dstTargetBlendDesc.SrcBlend = D3D11_BLEND_ONE;
+ dstTargetBlendDesc.SrcBlendAlpha = D3D11_BLEND_ONE;
+ dstTargetBlendDesc.DestBlend = D3D11_BLEND_ZERO;
+ dstTargetBlendDesc.DestBlendAlpha = D3D11_BLEND_ZERO;
+ }
+ else
+ {
+ dstTargetBlendDesc.BlendEnable = true;
+ dstTargetBlendDesc.BlendOp = translateBlendOp(srcTargetBlendDesc.color.op);
+ dstTargetBlendDesc.BlendOpAlpha = translateBlendOp(srcTargetBlendDesc.alpha.op);
+ dstTargetBlendDesc.SrcBlend = translateBlendFactor(srcTargetBlendDesc.color.srcFactor);
+ dstTargetBlendDesc.SrcBlendAlpha = translateBlendFactor(srcTargetBlendDesc.alpha.srcFactor);
+ dstTargetBlendDesc.DestBlend = translateBlendFactor(srcTargetBlendDesc.color.dstFactor);
+ dstTargetBlendDesc.DestBlendAlpha = translateBlendFactor(srcTargetBlendDesc.alpha.dstFactor);
+ }
+
+ dstTargetBlendDesc.RenderTargetWriteMask = translateRenderTargetWriteMask(srcTargetBlendDesc.writeMask);
+ }
+
+ dstDesc.IndependentBlendEnable = srcDesc.targetCount > 1;
+ dstDesc.AlphaToCoverageEnable = srcDesc.alphaToCoverateEnable;
+
+ SLANG_RETURN_ON_FAIL(m_device->CreateBlendState(
+ &dstDesc,
+ blendState.writeRef()));
+ }
+
RefPtr<GraphicsPipelineStateImpl> state = new GraphicsPipelineStateImpl();
state->m_program = programImpl;
state->m_stencilRef = desc.depthStencil.stencilRef;
state->m_depthStencilState = depthStencilState;
state->m_rasterizerState = rasterizerState;
+ state->m_blendState = blendState;
state->m_pipelineLayout = (PipelineLayoutImpl*) desc.pipelineLayout;
state->m_inputLayout = (InputLayoutImpl*) desc.inputLayout;
state->m_rtvCount = desc.renderTargetCount;
+ state->m_blendColor[0] = 0;
+ state->m_blendColor[1] = 0;
+ state->m_blendColor[2] = 0;
+ state->m_blendColor[3] = 0;
+ state->m_sampleMask = 0xFFFFFFFF;
*outState = state.detach();
return SLANG_OK;
diff --git a/tools/gfx/render-d3d12.cpp b/tools/gfx/render-d3d12.cpp
index 2d3b8f521..38ecaa5ef 100644
--- a/tools/gfx/render-d3d12.cpp
+++ b/tools/gfx/render-d3d12.cpp
@@ -88,6 +88,8 @@ public:
virtual void setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets) override;
virtual void setIndexBuffer(BufferResource* buffer, Format indexFormat, UInt offset) override;
virtual void setDepthStencilTarget(ResourceView* depthStencilView) override;
+ void setViewports(UInt count, Viewport const* viewports) override;
+ void setScissorRects(UInt count, ScissorRect const* rects) override;
virtual void setPipelineState(PipelineType pipelineType, PipelineState* state) override;
virtual void draw(UInt vertexCount, UInt startVertex) override;
virtual void drawIndexed(UInt indexCount, UInt startIndex, UInt baseVertex) override;
@@ -2545,6 +2547,48 @@ void D3D12Renderer::setDepthStencilTarget(ResourceView* depthStencilView)
{
}
+void D3D12Renderer::setViewports(UInt count, Viewport const* viewports)
+{
+ static const int kMaxViewports = D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
+ assert(count <= kMaxViewports);
+
+ D3D12_VIEWPORT dxViewports[kMaxViewports];
+ for(UInt ii = 0; ii < count; ++ii)
+ {
+ auto& inViewport = viewports[ii];
+ auto& dxViewport = dxViewports[ii];
+
+ dxViewport.TopLeftX = inViewport.originX;
+ dxViewport.TopLeftY = inViewport.originY;
+ dxViewport.Width = inViewport.extentX;
+ dxViewport.Height = inViewport.extentY;
+ dxViewport.MinDepth = inViewport.minZ;
+ dxViewport.MaxDepth = inViewport.maxZ;
+ }
+
+ m_commandList->RSSetViewports(count, dxViewports);
+}
+
+void D3D12Renderer::setScissorRects(UInt count, ScissorRect const* rects)
+{
+ static const int kMaxScissorRects = D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
+ assert(count <= kMaxScissorRects);
+
+ D3D12_RECT dxRects[kMaxScissorRects];
+ for(UInt ii = 0; ii < count; ++ii)
+ {
+ auto& inRect = rects[ii];
+ auto& dxRect = dxRects[ii];
+
+ dxRect.left = inRect.minX;
+ dxRect.top = inRect.minY;
+ dxRect.right = inRect.maxX;
+ dxRect.bottom = inRect.maxY;
+ }
+
+ m_commandList->RSSetScissorRects(count, dxRects);
+}
+
void D3D12Renderer::setPipelineState(PipelineType pipelineType, PipelineState* state)
{
m_currentPipelineState = (PipelineStateImpl*)state;
diff --git a/tools/gfx/render-gl.cpp b/tools/gfx/render-gl.cpp
index 3ab818fdd..d77271702 100644
--- a/tools/gfx/render-gl.cpp
+++ b/tools/gfx/render-gl.cpp
@@ -114,6 +114,8 @@ public:
virtual void setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets) override;
virtual void setIndexBuffer(BufferResource* buffer, Format indexFormat, UInt offset) override;
virtual void setDepthStencilTarget(ResourceView* depthStencilView) override;
+ void setViewports(UInt count, Viewport const* viewports) override;
+ void setScissorRects(UInt count, ScissorRect const* rects) override;
virtual void setPipelineState(PipelineType pipelineType, PipelineState* state) override;
virtual void draw(UInt vertexCount, UInt startVertex) override;
virtual void drawIndexed(UInt indexCount, UInt startIndex, UInt baseVertex) override;
@@ -1030,6 +1032,46 @@ void GLRenderer::setDepthStencilTarget(ResourceView* depthStencilView)
{
}
+void GLRenderer::setViewports(UInt count, Viewport const* viewports)
+{
+ assert(count == 1);
+ auto viewport = viewports[0];
+ glViewport(
+ (GLint) viewport.originX,
+ (GLint) viewport.originY,
+ (GLsizei) viewport.extentX,
+ (GLsizei) viewport.extentY);
+ glDepthRange(viewport.minZ, viewport.maxZ);
+}
+
+void GLRenderer::setScissorRects(UInt count, ScissorRect const* rects)
+{
+ assert(count <= 1);
+ if( count )
+ {
+ // TODO: this isn't goign to be quite right because of the
+ // flipped coordinate system in GL.
+ //
+ // The best way around this is probably to *always* render
+ // things internally into textures with "flipped" conventions,
+ // and then only deal with the flipping as part of a final
+ // "present" step that copies to the primary back-buffer.
+ //
+ auto rect = rects[0];
+ glScissor(
+ rect.minX,
+ rect.minY,
+ rect.maxX - rect.minX,
+ rect.maxY - rect.minY);
+
+ glEnable(GL_SCISSOR_TEST);
+ }
+ else
+ {
+ glDisable(GL_SCISSOR_TEST);
+ }
+}
+
void GLRenderer::setPipelineState(PipelineType pipelineType, PipelineState* state)
{
auto pipelineStateImpl = (PipelineStateImpl*) state;
diff --git a/tools/gfx/render-vk.cpp b/tools/gfx/render-vk.cpp
index 27926e0e6..aee45a86e 100644
--- a/tools/gfx/render-vk.cpp
+++ b/tools/gfx/render-vk.cpp
@@ -75,6 +75,8 @@ public:
virtual void setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets) override;
virtual void setIndexBuffer(BufferResource* buffer, Format indexFormat, UInt offset) override;
virtual void setDepthStencilTarget(ResourceView* depthStencilView) override;
+ void setViewports(UInt count, Viewport const* viewports) override;
+ void setScissorRects(UInt count, ScissorRect const* rects) override;
virtual void setPipelineState(PipelineType pipelineType, PipelineState* state) override;
virtual void draw(UInt vertexCount, UInt startVertex) override;
virtual void drawIndexed(UInt indexCount, UInt startIndex, UInt baseVertex) override;
@@ -1877,6 +1879,50 @@ void VKRenderer::setDepthStencilTarget(ResourceView* depthStencilView)
{
}
+void VKRenderer::setViewports(UInt count, Viewport const* viewports)
+{
+ static const int kMaxViewports = 8; // TODO: base on device caps
+ assert(count <= kMaxViewports);
+
+ VkViewport vkViewports[kMaxViewports];
+ for(UInt ii = 0; ii < count; ++ii)
+ {
+ auto& inViewport = viewports[ii];
+ auto& vkViewport = vkViewports[ii];
+
+ vkViewport.x = inViewport.originX;
+ vkViewport.y = inViewport.originY;
+ vkViewport.width = inViewport.extentX;
+ vkViewport.height = inViewport.extentY;
+ vkViewport.minDepth = inViewport.minZ;
+ vkViewport.maxDepth = inViewport.maxZ;
+ }
+
+ VkCommandBuffer commandBuffer = m_deviceQueue.getCommandBuffer();
+ m_api.vkCmdSetViewport(commandBuffer, 0, count, vkViewports);
+}
+
+void VKRenderer::setScissorRects(UInt count, ScissorRect const* rects)
+{
+ static const int kMaxScissorRects = 8; // TODO: base on device caps
+ assert(count <= kMaxScissorRects);
+
+ VkRect2D vkRects[kMaxScissorRects];
+ for(UInt ii = 0; ii < count; ++ii)
+ {
+ auto& inRect = rects[ii];
+ auto& vkRect = vkRects[ii];
+
+ vkRect.offset.x = inRect.minX;
+ vkRect.offset.y = inRect.minY;
+ vkRect.extent.width = inRect.maxX - inRect.minX;
+ vkRect.extent.height = inRect.maxY - inRect.minY;
+ }
+
+ VkCommandBuffer commandBuffer = m_deviceQueue.getCommandBuffer();
+ m_api.vkCmdSetScissor(commandBuffer, 0, count, vkRects);
+}
+
void VKRenderer::setPipelineState(PipelineType pipelineType, PipelineState* state)
{
m_currentPipeline = (PipelineStateImpl*)state;
diff --git a/tools/gfx/render.cpp b/tools/gfx/render.cpp
index 8f887b491..38af85f79 100644
--- a/tools/gfx/render.cpp
+++ b/tools/gfx/render.cpp
@@ -55,6 +55,7 @@ const Resource::DescBase& Resource::getDescBase() const
uint8_t(sizeof(uint32_t)), // RGBA_Unorm_UInt8,
+ uint8_t(sizeof(uint16_t)), // R_UInt16,
uint8_t(sizeof(uint32_t)), // R_UInt32,
uint8_t(sizeof(float)), // D_Float32,
diff --git a/tools/gfx/render.h b/tools/gfx/render.h
index b43152b68..f59a5ef9f 100644
--- a/tools/gfx/render.h
+++ b/tools/gfx/render.h
@@ -155,6 +155,7 @@ enum class Format
RGBA_Unorm_UInt8,
+ R_UInt16,
R_UInt32,
D_Float32,
@@ -647,6 +648,80 @@ struct RasterizerDesc
bool antialiasedLineEnable = false;
};
+enum class LogicOp
+{
+ NoOp,
+};
+
+enum class BlendOp
+{
+ Add,
+ Subtract,
+ ReverseSubtract,
+ Min,
+ Max,
+};
+
+enum class BlendFactor
+{
+ Zero,
+ One,
+ SrcColor,
+ InvSrcColor,
+ SrcAlpha,
+ InvSrcAlpha,
+ DestAlpha,
+ InvDestAlpha,
+ DestColor,
+ InvDestColor,
+ SrcAlphaSaturate,
+ BlendColor,
+ InvBlendColor,
+ SecondarySrcColor,
+ InvSecondarySrcColor,
+ SecondarySrcAlpha,
+ InvSecondarySrcAlpha,
+};
+
+namespace RenderTargetWriteMask
+{
+ typedef uint8_t Type;
+ enum
+ {
+ EnableNone = 0,
+ EnableRed = 0x01,
+ EnableGreen = 0x02,
+ EnableBlue = 0x04,
+ EnableAlpha = 0x08,
+ EnableAll = 0x0F,
+ };
+};
+typedef RenderTargetWriteMask::Type RenderTargetWriteMaskT;
+
+struct AspectBlendDesc
+{
+ BlendFactor srcFactor = BlendFactor::One;
+ BlendFactor dstFactor = BlendFactor::Zero;
+ BlendOp op = BlendOp::Add;
+};
+
+struct TargetBlendDesc
+{
+ AspectBlendDesc color;
+ AspectBlendDesc alpha;
+
+ LogicOp logicOp = LogicOp::NoOp;
+ RenderTargetWriteMaskT writeMask = RenderTargetWriteMask::EnableAll;
+};
+
+struct BlendDesc
+{
+ TargetBlendDesc const* targets = nullptr;
+ UInt targetCount = 0;
+
+ bool alphaToCoverateEnable = false;
+};
+
struct GraphicsPipelineStateDesc
{
ShaderProgram* program;
@@ -657,6 +732,7 @@ struct GraphicsPipelineStateDesc
UInt renderTargetCount;
DepthStencilDesc depthStencil;
RasterizerDesc rasterizer;
+ BlendDesc blend;
};
struct ComputePipelineStateDesc
@@ -670,6 +746,24 @@ class PipelineState : public Slang::RefObject
public:
};
+struct ScissorRect
+{
+ Int minX;
+ Int minY;
+ Int maxX;
+ Int maxY;
+};
+
+struct Viewport
+{
+ float originX = 0.0f;
+ float originY = 0.0f;
+ float extentX = 0.0f;
+ float extentY = 0.0f;
+ float minZ = 0.0f;
+ float maxZ = 1.0f;
+};
+
class Renderer: public Slang::RefObject
{
public:
@@ -823,6 +917,18 @@ public:
virtual void setDepthStencilTarget(ResourceView* depthStencilView) = 0;
+ virtual void setViewports(UInt count, Viewport const* viewports) = 0;
+ inline void setViewport(Viewport const& viewport)
+ {
+ setViewports(1, &viewport);
+ }
+
+ virtual void setScissorRects(UInt count, ScissorRect const* rects) = 0;
+ inline void setScissorRect(ScissorRect const& rect)
+ {
+ setScissorRects(1, &rect);
+ }
+
virtual void setPipelineState(PipelineType pipelineType, PipelineState* state) = 0;
virtual void draw(UInt vertexCount, UInt startVertex = 0) = 0;
diff --git a/tools/gfx/window.cpp b/tools/gfx/window.cpp
index ee9f50813..9bc63b896 100644
--- a/tools/gfx/window.cpp
+++ b/tools/gfx/window.cpp
@@ -111,22 +111,53 @@ int runWindowsApplication(
struct Window
{
HWND handle;
+ WNDPROC nativeHook;
};
+void setNativeWindowHook(Window* window, WNDPROC proc)
+{
+ window->nativeHook = proc;
+}
+
static LRESULT CALLBACK windowProc(
HWND windowHandle,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
+ Window* window = (Window*) GetWindowLongPtrW(windowHandle, GWLP_USERDATA);
+
+ // Give the installed filter a chance to intercept messages.
+ // (This is used for ImGui)
+ if( window )
+ {
+ if(auto nativeHook = window->nativeHook)
+ {
+ auto result = nativeHook(windowHandle, message, wParam, lParam);
+ if(result)
+ return result;
+ }
+ }
+
// TODO: Actually implement some reasonable logic here.
switch (message)
{
+ case WM_CREATE:
+ {
+ auto createInfo = (CREATESTRUCTW*) lParam;
+ window = (Window*) createInfo->lpCreateParams;
+ window->handle = windowHandle;
+
+ SetWindowLongPtrW(windowHandle, GWLP_USERDATA, (LONG)window);
+ }
+ break;
+
case WM_CLOSE:
PostQuitMessage(0);
return 0;
}
+
return DefWindowProcW(windowHandle, message, wParam, lParam);
}
@@ -159,6 +190,8 @@ static ATOM getWindowClassAtom()
Window* createWindow(WindowDesc const& desc)
{
Window* window = new Window();
+ window->handle = nullptr;
+ window->nativeHook = nullptr;
OSString windowTitle(desc.title);