summaryrefslogtreecommitdiffstats
path: root/tools/render-test
diff options
context:
space:
mode:
Diffstat (limited to 'tools/render-test')
-rw-r--r--tools/render-test/main.cpp19
-rw-r--r--tools/render-test/options.cpp4
-rw-r--r--tools/render-test/options.h1
-rw-r--r--tools/render-test/render-d3d11.cpp32
-rw-r--r--tools/render-test/render-gl.cpp309
-rw-r--r--tools/render-test/render.h2
-rw-r--r--tools/render-test/slang-support.cpp4
7 files changed, 359 insertions, 12 deletions
diff --git a/tools/render-test/main.cpp b/tools/render-test/main.cpp
index e444a8387..2746c505d 100644
--- a/tools/render-test/main.cpp
+++ b/tools/render-test/main.cpp
@@ -262,16 +262,26 @@ int main(
// Next, we create a window using that window class.
+ // We will create a borderless window since our screen-capture logic in GL
+ // seems to get thrown off by having to deal with a window frame.
+ DWORD windowStyle = WS_POPUP;
DWORD windowExtendedStyle = 0;
- DWORD windowStyle = 0;
- LPWSTR windowName = L"Slang Hello World";
+
+
+ RECT windowRect = { 0, 0, gWindowWidth, gWindowHeight };
+ AdjustWindowRectEx(&windowRect, windowStyle, /*hasMenu=*/false, windowExtendedStyle);
+
+ auto width = windowRect.right - windowRect.left;
+ auto height = windowRect.bottom - windowRect.top;
+
+ LPWSTR windowName = L"Slang Render Test";
HWND windowHandle = CreateWindowExW(
windowExtendedStyle,
(LPWSTR)windowClassAtom,
windowName,
windowStyle,
0, 0, // x, y
- gWindowWidth, gWindowHeight,
+ width, height,
NULL, // parent
NULL, // menu
instance,
@@ -291,6 +301,7 @@ int main(
renderer = createD3D11Renderer();
break;
+ case Mode::GLSL:
case Mode::GLSLCrossCompile:
renderer = createGLRenderer();
break;
@@ -349,6 +360,8 @@ int main(
// Whenver we don't have Windows events to process,
// we render a frame.
+ static const float kClearColor[] = { 0.25, 0.25, 0.25, 1.0 };
+ renderer->setClearColor(kClearColor);
renderer->clearFrame();
renderFrameInner(renderer);
diff --git a/tools/render-test/options.cpp b/tools/render-test/options.cpp
index 9cfbb81fb..260e6f46c 100644
--- a/tools/render-test/options.cpp
+++ b/tools/render-test/options.cpp
@@ -56,6 +56,10 @@ void parseOptions(int* argc, char** argv)
{
gOptions.mode = Mode::HLSL;
}
+ else if( strcmp(arg, "-glsl") == 0 )
+ {
+ gOptions.mode = Mode::GLSL;
+ }
else if( strcmp(arg, "-slang") == 0 )
{
gOptions.mode = Mode::Slang;
diff --git a/tools/render-test/options.h b/tools/render-test/options.h
index ffb07bc93..81617630f 100644
--- a/tools/render-test/options.h
+++ b/tools/render-test/options.h
@@ -12,6 +12,7 @@ enum class Mode
{
Slang,
HLSL,
+ GLSL,
GLSLCrossCompile,
};
diff --git a/tools/render-test/render-d3d11.cpp b/tools/render-test/render-d3d11.cpp
index ab981bd45..4f1071905 100644
--- a/tools/render-test/render-d3d11.cpp
+++ b/tools/render-test/render-d3d11.cpp
@@ -362,6 +362,13 @@ ID3DBlob* compileHLSLShader(
flags |= D3DCOMPILE_DEBUG;
flags |= D3DCOMPILE_OPTIMIZATION_LEVEL0 | D3DCOMPILE_SKIP_OPTIMIZATION;
+ // We will always define `__HLSL__` when compiling here, so that
+ // input code can react differently to being compiled as pure HLSL.
+ D3D_SHADER_MACRO defines[] = {
+ { "__HLSL__", "1" },
+ { nullptr, nullptr },
+ };
+
// The `D3DCompile` entry point takes a bunch of parameters, but we
// don't really need most of them for Slang-generated code.
ID3DBlob* dxShaderBlob = nullptr;
@@ -370,7 +377,7 @@ ID3DBlob* compileHLSLShader(
source,
strlen(source),
sourcePath,
- nullptr,
+ &defines[0],
nullptr,
entryPointName,
dxProfileName,
@@ -383,8 +390,14 @@ ID3DBlob* compileHLSLShader(
// then we will print them out (whether or not the compilation failed).
if( dxErrorBlob )
{
+ fputs(
+ (char const*)dxErrorBlob->GetBufferPointer(),
+ stderr);
+ fflush(stderr);
+
OutputDebugStringA(
(char const*)dxErrorBlob->GetBufferPointer());
+
dxErrorBlob->Release();
}
@@ -523,7 +536,13 @@ public:
DXGI_SWAP_CHAIN_DESC dxSwapChainDesc = { 0 };
dxSwapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
- dxSwapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
+
+ // Note(tfoley): Disabling sRGB for DX back buffer for now, so that we
+ // can get consistent output with OpenGL, where setting up sRGB will
+ // probably be more involved.
+// dxSwapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
+ dxSwapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+
dxSwapChainDesc.SampleDesc.Count = 1;
dxSwapChainDesc.SampleDesc.Quality = 0;
dxSwapChainDesc.BufferCount = 2;
@@ -601,12 +620,17 @@ public:
dxImmediateContext->RSSetViewports(1, &dxViewport);
}
+ float clearColor[4] = { 0, 0, 0, 0 };
+ virtual void setClearColor(float const* color) override
+ {
+ memcpy(clearColor, color, sizeof(clearColor));
+ }
+
virtual void clearFrame() override
{
- static const float kClearColor[] = { 0.25, 0.25, 0.25, 1.0 };
dxImmediateContext->ClearRenderTargetView(
dxBackBufferRTV,
- kClearColor);
+ clearColor);
}
virtual void presentFrame() override
diff --git a/tools/render-test/render-gl.cpp b/tools/render-test/render-gl.cpp
index 545dd2e44..ea56a10b4 100644
--- a/tools/render-test/render-gl.cpp
+++ b/tools/render-test/render-gl.cpp
@@ -4,9 +4,12 @@
#include "options.h"
#include "render.h"
+#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
+#include "external/stb/stb_image_write.h"
+
// TODO(tfoley): eventually we should be able to run these
// tests on non-Windows targets to confirm that cross-compilation
// at least *works* on those platforms...
@@ -44,7 +47,18 @@
F(glGetProgramInfoLog, PFNGLGETPROGRAMINFOLOGPROC) \
F(glDeleteProgram, PFNGLDELETEPROGRAMPROC) \
F(glGetShaderInfoLog, PFNGLGETSHADERINFOLOGPROC) \
- /* emtty */
+ F(glGenBuffers, PFNGLGENBUFFERSPROC) \
+ F(glBindBuffer, PFNGLBINDBUFFERPROC) \
+ F(glBufferData, PFNGLBUFFERDATAPROC) \
+ F(glMapBuffer, PFNGLMAPBUFFERPROC) \
+ F(glUnmapBuffer, PFNGLUNMAPBUFFERPROC) \
+ F(glUseProgram, PFNGLUSEPROGRAMPROC) \
+ F(glBindBufferBase, PFNGLBINDBUFFERBASEPROC) \
+ F(glVertexAttribPointer, PFNGLVERTEXATTRIBPOINTERPROC) \
+ F(glEnableVertexAttribArray, PFNGLENABLEVERTEXATTRIBARRAYPROC) \
+ F(glDisableVertexAttribArray, PFNGLDISABLEVERTEXATTRIBARRAYPROC) \
+ F(glDebugMessageCallback, PFNGLDEBUGMESSAGECALLBACKPROC) \
+ /* end */
namespace renderer_test {
@@ -92,6 +106,60 @@ public:
#define LOAD_GL_EXTENSION_FUNC(NAME, TYPE) NAME = (TYPE) wglGetProcAddress(#NAME);
MAP_GL_EXTENSION_FUNCS(LOAD_GL_EXTENSION_FUNC)
#undef LOAD_GL_EXTENSION_FUNC
+
+
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_CULL_FACE);
+
+ glViewport(0, 0, gWindowWidth, gWindowHeight);
+
+ if (glDebugMessageCallback)
+ {
+ glEnable(GL_DEBUG_OUTPUT);
+ glDebugMessageCallback(staticDebugCallback, this);
+ }
+ }
+
+ void debugCallback(
+ GLenum source,
+ GLenum type,
+ GLuint id,
+ GLenum severity,
+ GLsizei length,
+ GLchar const* message)
+ {
+ OutputDebugStringA("GL: ");
+ OutputDebugStringA(message);
+ OutputDebugStringA("\n");
+
+ switch (type)
+ {
+ case GL_DEBUG_TYPE_ERROR:
+ assert(!"unexpected");
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ static void APIENTRY staticDebugCallback(
+ GLenum source,
+ GLenum type,
+ GLuint id,
+ GLenum severity,
+ GLsizei length,
+ GLchar const* message,
+ void const* userParam)
+ {
+ ((GLRenderer*) userParam)->debugCallback(
+ source, type, id, severity, length, message);
+ }
+
+ float clearColor[4] = { 0, 0, 0, 0 };
+ virtual void setClearColor(float const* color) override
+ {
+ glClearColor(color[0], color[1], color[2], color[3]);
}
virtual void clearFrame() override
@@ -107,7 +175,51 @@ public:
virtual void captureScreenShot(char const* outputPath) override
{
+ int width = gWindowWidth;
+ int height = gWindowHeight;
+
+ int components = 4;
+ int rowStride = width*components;
+
+ GLubyte* buffer = (GLubyte*)malloc(components * width * height);
+
+ glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+
+ // OpenGL's "upside down" convention bites us here, so we need
+ // to flip the data in the buffer by swapping rows
+ int halfHeight = height / 2;
+ for (int hh = 0; hh < halfHeight; ++hh)
+ {
+ // Get a pointer to the row data, and a pointer
+ // to the row on the "other end" of the image
+ GLubyte* rowA = buffer + rowStride*hh;
+ GLubyte* rowB = buffer + rowStride*(height - (hh + 1));
+ for (int ii = 0; ii < rowStride; ++ii)
+ {
+ auto a = rowA[ii];
+ auto b = rowB[ii];
+
+ rowA[ii] = b;
+ rowB[ii] = a;
+ }
+ }
+
+ //
+
+ int stbResult = stbi_write_png(
+ outputPath,
+ width,
+ height,
+ components,
+ buffer,
+ rowStride);
+ if( !stbResult )
+ {
+ assert(!"unexpected");
+ }
+
+ delete(buffer);
}
virtual ShaderCompiler* getShaderCompiler() override
@@ -117,46 +229,203 @@ public:
virtual Buffer* createBuffer(BufferDesc const& desc) override
{
- return nullptr;
+ // TODO: should derive target from desc...
+ GLenum target = GL_UNIFORM_BUFFER;
+
+ // TODO: should derive from desc...
+ GLenum usage = GL_DYNAMIC_DRAW;
+
+ GLuint bufferID = 0;
+ glGenBuffers(1, &bufferID);
+ glBindBuffer(target, bufferID);
+
+ glBufferData(target, desc.size, desc.initData, usage);
+
+ return (Buffer*)(uintptr_t)bufferID;
+ }
+
+ struct VertexAttributeFormat
+ {
+ GLint componentCount;
+ GLenum componentType;
+ GLboolean normalized;
+ };
+
+ struct VertexAttributeDesc
+ {
+ VertexAttributeFormat format;
+ GLuint streamIndex;
+ GLsizei offset;
+ };
+
+ enum
+ {
+ kMaxVertexStreams = 16,
+ };
+
+ struct InputLayoutImpl
+ {
+ VertexAttributeDesc attributes[kMaxVertexStreams];
+ UInt attributeCount = 0;
+ };
+
+ static VertexAttributeFormat getVertexAttributeFormat(
+ Format format)
+ {
+ switch (format)
+ {
+ default: assert(!"unexpected"); return VertexAttributeFormat();
+
+ #define CASE(NAME, COUNT, TYPE, NORMALIZED) \
+ case Format::NAME: do { VertexAttributeFormat result = {COUNT, TYPE, NORMALIZED}; return result; } while (0)
+
+ CASE(RGB_Float32, 3, GL_FLOAT, GL_FALSE);
+
+ #undef CASE
+
+ }
}
virtual InputLayout* createInputLayout(InputElementDesc const* inputElements, UInt inputElementCount) override
{
- return nullptr;
+ InputLayoutImpl* inputLayout = new InputLayoutImpl();
+
+ inputLayout->attributeCount = inputElementCount;
+ for (UInt ii = 0; ii < inputElementCount; ++ii)
+ {
+ auto& inputAttr = inputElements[ii];
+ auto& glAttr = inputLayout->attributes[ii];
+
+ glAttr.streamIndex = 0;
+ glAttr.format = getVertexAttributeFormat(inputAttr.format);
+ glAttr.offset = inputAttr.offset;
+ }
+
+ return (InputLayout*)inputLayout;
}
virtual void* map(Buffer* buffer, MapFlavor flavor) override
{
- return nullptr;
+ GLenum target = GL_UNIFORM_BUFFER;
+
+ GLuint access = 0;
+ switch (flavor)
+ {
+ case MapFlavor::WriteDiscard:
+ access = GL_WRITE_ONLY;
+ break;
+ }
+
+ auto bufferID = (GLuint)(uintptr_t)buffer;
+ glBindBuffer(target, bufferID);
+
+ return glMapBuffer(target, access);
}
virtual void unmap(Buffer* buffer) override
{
+ GLenum target = GL_UNIFORM_BUFFER;
+
+ auto bufferID = (GLuint)(uintptr_t)buffer;
+ glUnmapBuffer(target);
}
+ InputLayoutImpl* boundInputLayout = nullptr;
+
virtual void setInputLayout(InputLayout* inputLayout) override
{
+ boundInputLayout = (InputLayoutImpl*) inputLayout;
}
+ GLenum boundPrimitiveTopology = GL_TRIANGLES;
+
virtual void setPrimitiveTopology(PrimitiveTopology topology) override
{
+ GLenum glTopology = 0;
+ switch (topology)
+ {
+ #define CASE(NAME, VALUE) case PrimitiveTopology::NAME: glTopology = VALUE; break
+
+ CASE(TriangleList, GL_TRIANGLES);
+
+ #undef CASE
+ }
+ boundPrimitiveTopology = glTopology;
}
+ GLuint boundVertexStreamBuffers[kMaxVertexStreams];
+ UInt boundVertexStreamStrides[kMaxVertexStreams];
+ UInt boundVertexStreamOffsets[kMaxVertexStreams];
+
virtual void setVertexBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* strides, UInt const* offsets) override
{
+ for (UInt ii = 0; ii < slotCount; ++ii)
+ {
+ UInt slot = startSlot + ii;
+
+ Buffer* buffer = buffers[ii];
+ GLuint bufferID = (GLuint)(uintptr_t)buffer;
+
+ boundVertexStreamBuffers[slot] = bufferID;
+ boundVertexStreamStrides[slot] = strides[ii];
+ boundVertexStreamOffsets[slot] = offsets[ii];
+ }
}
virtual void setShaderProgram(ShaderProgram* program) override
{
+ GLuint programID = (GLuint)(uintptr_t)program;
+ glUseProgram(programID);
}
virtual void setConstantBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* offsets) override
{
+ for (UInt ii = 0; ii < slotCount; ++ii)
+ {
+ UInt slot = startSlot + ii;
+
+ Buffer* buffer = buffers[ii];
+ GLuint bufferID = (GLuint)(uintptr_t)buffer;
+
+ assert(!offsets || !offsets[ii]);
+
+ glBindBufferBase(GL_UNIFORM_BUFFER, slot, bufferID);
+ }
}
+ void flushStateForDraw()
+ {
+ auto layout = this->boundInputLayout;
+ auto attrCount = layout->attributeCount;
+ for (UInt ii = 0; ii < attrCount; ++ii)
+ {
+ auto& attr = layout->attributes[ii];
+
+ auto streamIndex = attr.streamIndex;
+
+ glBindBuffer(GL_ARRAY_BUFFER, boundVertexStreamBuffers[streamIndex]);
+
+ glVertexAttribPointer(
+ ii,
+ attr.format.componentCount,
+ attr.format.componentType,
+ attr.format.normalized,
+ boundVertexStreamStrides[streamIndex],
+ (GLvoid*)(attr.offset + boundVertexStreamOffsets[streamIndex]));
+
+ glEnableVertexAttribArray(ii);
+ }
+ for (UInt ii = attrCount; ii < kMaxVertexStreams; ++ii)
+ {
+ glDisableVertexAttribArray(ii);
+ }
+ }
virtual void draw(UInt vertexCount, UInt startVertex = 0) override
{
+ flushStateForDraw();
+
+ glDrawArrays(boundPrimitiveTopology, startVertex, vertexCount);
}
// ShaderCompiler interface
@@ -204,7 +473,37 @@ public:
{
auto shaderID = glCreateShader(stage);
- glShaderSource(shaderID, 1, &source, nullptr);
+ char const* stagePrelude = "\n";
+ switch (stage)
+ {
+#define CASE(NAME) case GL_##NAME##_SHADER: stagePrelude = "#define __GLSL_" #NAME "__ 1\n"; break
+
+ CASE(VERTEX);
+ CASE(TESS_CONTROL);
+ CASE(TESS_EVALUATION);
+ CASE(GEOMETRY);
+ CASE(FRAGMENT);
+ CASE(COMPUTE);
+
+#undef CASE
+ }
+
+ char const* prelude =
+ "#define __GLSL__ 1\n"
+ ;
+
+ char const* sourceStrings[] =
+ {
+ stagePrelude,
+ prelude,
+ source,
+ };
+
+ glShaderSource(
+ shaderID,
+ sizeof(sourceStrings) / sizeof(sourceStrings[0]),
+ &sourceStrings[0],
+ nullptr);
glCompileShader(shaderID);
GLint success = GL_FALSE;
diff --git a/tools/render-test/render.h b/tools/render-test/render.h
index a30bf98f9..afa279c66 100644
--- a/tools/render-test/render.h
+++ b/tools/render-test/render.h
@@ -79,7 +79,9 @@ class Renderer
public:
virtual void initialize(void* inWindowHandle) = 0;
+ virtual void setClearColor(float const* color) = 0;
virtual void clearFrame() = 0;
+
virtual void presentFrame() = 0;
virtual void captureScreenShot(char const* outputPath) = 0;
diff --git a/tools/render-test/slang-support.cpp b/tools/render-test/slang-support.cpp
index 5aafc562e..06a11ad4c 100644
--- a/tools/render-test/slang-support.cpp
+++ b/tools/render-test/slang-support.cpp
@@ -20,6 +20,10 @@ struct SlangShaderCompilerWrapper : public ShaderCompiler
spSetCodeGenTarget(slangRequest, target);
+ // Define a macro so that shader code in a test can detect when it is being
+ // compiled as Slang source code.
+ spAddPreprocessorDefine(slangRequest, "__SLANG__", "1");
+
int translationUnitIndex = spAddTranslationUnit(slangRequest, SLANG_SOURCE_LANGUAGE_SLANG, nullptr);
spAddTranslationUnitSourceString(slangRequest, translationUnitIndex, request.source.path, request.source.text);