In essence, the goal is to separate the d3d12 backend. Just separate the compiler first, though, to make the diff easier to read.
NOTE TO SELF: Generate this diff with -C
Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
Makefile.am | 41 +-
include/private/vkd3d_test.h | 19 +-
tests/shader_runner.c | 862 +++++++++++++++++++++++++++++++++++
tests/shader_runner.h | 29 ++
tests/shader_runner_d3d12.c | 847 +---------------------------------
5 files changed, 947 insertions(+), 851 deletions(-)
create mode 100644 tests/shader_runner.c
create mode 100644 tests/shader_runner.h
diff --git a/Makefile.am b/Makefile.am
index 20fee06d0..84aba0ee7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -50,9 +50,6 @@ vkd3d_cross_tests = \
tests/d3d12_invalid_usage \
tests/hlsl_d3d12
-vkd3d_shader_runners = \
- tests/shader_runner_d3d12
-
vkd3d_shader_tests = \
tests/abs.shader_test \
tests/cast-to-float.shader_test \
@@ -113,7 +110,8 @@ vkd3d_shader_tests = \
vkd3d_test_headers = \
tests/d3d12_crosstest.h \
- tests/d3d12_test_utils.h
+ tests/d3d12_test_utils.h \
+ tests/shader_runner.h
vkd3d_demos = \
demos/vkd3d-gears \
@@ -273,15 +271,18 @@ AM_DEFAULT_SOURCE_EXT = .c
TEST_EXTENSIONS = .shader_test
if BUILD_TESTS
-check_PROGRAMS = $(vkd3d_tests) $(vkd3d_cross_tests) $(vkd3d_shader_runners)
+check_PROGRAMS = $(vkd3d_tests) $(vkd3d_cross_tests) tests/shader_runner
TESTS = $(vkd3d_tests) $(vkd3d_cross_tests) $(vkd3d_shader_tests)
tests_d3d12_LDADD = $(LDADD) @PTHREAD_LIBS@ @VULKAN_LIBS@
tests_d3d12_invalid_usage_LDADD = $(LDADD) @VULKAN_LIBS@
tests_hlsl_d3d12_LDADD = $(LDADD) @VULKAN_LIBS@
-tests_shader_runner_d3d12_LDADD = $(LDADD) @VULKAN_LIBS@
+tests_shader_runner_LDADD = $(LDADD) @VULKAN_LIBS@
+tests_shader_runner_SOURCES = \
+ tests/shader_runner.c \
+ tests/shader_runner_d3d12.c
tests_vkd3d_api_LDADD = libvkd3d.la @VULKAN_LIBS@
tests_vkd3d_shader_api_LDADD = libvkd3d-shader.la
-SHADER_TEST_LOG_COMPILER = tests/shader_runner_d3d12
+SHADER_TEST_LOG_COMPILER = tests/shader_runner
XFAIL_TESTS = \
tests/cast-to-float.shader_test \
tests/cast-to-half.shader_test \
@@ -388,14 +389,17 @@ CROSS_CPPFLAGS = -I$(srcdir)/include -I$(srcdir)/include/private -I$(builddir)/i
CROSS_CFLAGS = -g -O2 -Wall -municode ${CROSS_CPPFLAGS}
EXTRA_DIST += $(cross_implibs:=.cross32.def) $(cross_implibs:=.cross64.def)
+shader_runner_cross_sources = \
+ $(srcdir)/tests/shader_runner.c \
+ $(srcdir)/tests/shader_runner_d3d12.c
+
if HAVE_CROSSTARGET32
CROSS32_CC = @CROSSCC32@
CROSS32_DLLTOOL = @CROSSTARGET32@-dlltool
CROSS32_IMPLIBS = $(cross_implibs:=.cross32.a)
CROSS32_EXEFILES = $(vkd3d_cross_tests:=.cross32.exe) \
- $(vkd3d_demos:demos/vkd3d-%=demos/%.cross32.exe) \
- $(vkd3d_shader_runners:=.cross32.exe)
-CROSS32_FILES = $(CROSS32_IMPLIBS) $(CROSS32_EXEFILES)
+ $(vkd3d_demos:demos/vkd3d-%=demos/%.cross32.exe)
+CROSS32_FILES = $(CROSS32_IMPLIBS) $(CROSS32_EXEFILES) tests/shader_runner.cross32.exe
CLEANFILES += $(CROSS32_FILES)
crosstest32: $(CROSS32_FILES)
@@ -411,6 +415,12 @@ $(CROSS32_EXEFILES): %.cross32.exe: %.c $(CROSS32_IMPLIBS) $(widl_headers)
$(AM_V_CCLD)depbase=`echo $@ | $(SED) 's![^/]*$$!$(DEPDIR)/&!;s!\.exe$$!!'`; \
$(CROSS32_CC) $(CROSS_CFLAGS) -MT $@ -MD -MP -MF $$depbase.Tpo -o $@ $< $(CROSS32_IMPLIBS) -ldxgi -lgdi32 -ld3dcompiler_47 && \
$(am__mv) $$depbase.Tpo $$depbase.Po
+
+tests/shader_runner.cross32.exe: $(shader_runner_cross_sources) $(CROSS32_IMPLIBS) $(widl_headers)
+ $(AM_V_CCLD)depbase=`echo $@ | sed 's![^/]*$$!$(DEPDIR)/&!;s!\.exe$$!!'`; \
+ $(CROSS32_CC) $(CROSS_CFLAGS) -MT $@ -MD -MP -MF $$depbase.Tpo -o $@ $(shader_runner_cross_sources) $(CROSS32_IMPLIBS) -ldxgi -lgdi32 -ld3dcompiler_47 && \
+ $(am__mv) $$depbase.Tpo $$depbase.Po
+
else
crosstest32:
endif
@@ -420,9 +430,8 @@ CROSS64_CC = @CROSSCC64@
CROSS64_DLLTOOL = @CROSSTARGET64@-dlltool
CROSS64_IMPLIBS = $(cross_implibs:=.cross64.a)
CROSS64_EXEFILES = $(vkd3d_cross_tests:=.cross64.exe) \
- $(vkd3d_demos:demos/vkd3d-%=demos/%.cross64.exe) \
- $(vkd3d_shader_runners:=.cross64.exe)
-CROSS64_FILES = $(CROSS64_IMPLIBS) $(CROSS64_EXEFILES)
+ $(vkd3d_demos:demos/vkd3d-%=demos/%.cross64.exe)
+CROSS64_FILES = $(CROSS64_IMPLIBS) $(CROSS64_EXEFILES) tests/shader_runner.cross64.exe
CLEANFILES += $(CROSS64_FILES)
crosstest64: $(CROSS64_FILES)
@@ -438,6 +447,12 @@ $(CROSS64_EXEFILES): %.cross64.exe: %.c $(CROSS64_IMPLIBS) $(widl_headers)
$(AM_V_CCLD)depbase=`echo $@ | sed 's![^/]*$$!$(DEPDIR)/&!;s!\.exe$$!!'`; \
$(CROSS64_CC) $(CROSS_CFLAGS) -MT $@ -MD -MP -MF $$depbase.Tpo -o $@ $< $(CROSS64_IMPLIBS) -ldxgi -lgdi32 -ld3dcompiler_47 && \
$(am__mv) $$depbase.Tpo $$depbase.Po
+
+tests/shader_runner.cross64.exe: $(shader_runner_cross_sources) $(CROSS64_IMPLIBS) $(widl_headers)
+ $(AM_V_CCLD)depbase=`echo $@ | sed 's![^/]*$$!$(DEPDIR)/&!;s!\.exe$$!!'`; \
+ $(CROSS64_CC) $(CROSS_CFLAGS) -MT $@ -MD -MP -MF $$depbase.Tpo -o $@ $(shader_runner_cross_sources) $(CROSS64_IMPLIBS) -ldxgi -lgdi32 -ld3dcompiler_47 && \
+ $(am__mv) $$depbase.Tpo $$depbase.Po
+
else
crosstest64:
endif
diff --git a/include/private/vkd3d_test.h b/include/private/vkd3d_test.h
index 6b8763dde..0cc7fe4f3 100644
--- a/include/private/vkd3d_test.h
+++ b/include/private/vkd3d_test.h
@@ -28,16 +28,15 @@
#include <stdlib.h>
#include <string.h>
-static void vkd3d_test_main(int argc, char **argv);
-static const char *vkd3d_test_name;
-static const char *vkd3d_test_platform = "other";
+extern const char *vkd3d_test_name;
+extern const char *vkd3d_test_platform;
static void vkd3d_test_start_todo(bool is_todo);
static int vkd3d_test_loop_todo(void);
static void vkd3d_test_end_todo(void);
#define START_TEST(name) \
- static const char *vkd3d_test_name = #name; \
+ const char *vkd3d_test_name = #name; \
static void vkd3d_test_main(int argc, char **argv)
/*
@@ -100,7 +99,7 @@ static void vkd3d_test_end_todo(void);
#define todo todo_if(true)
-static struct
+struct vkd3d_test_state
{
LONG success_count;
LONG failure_count;
@@ -120,7 +119,8 @@ static struct
const char *test_name_filter;
char context[1024];
-} vkd3d_test_state;
+};
+extern struct vkd3d_test_state vkd3d_test_state;
static bool
vkd3d_test_platform_is_windows(void)
@@ -253,6 +253,12 @@ vkd3d_test_debug(const char *fmt, ...)
printf("%s\n", buffer);
}
+#ifndef VKD3D_TEST_NO_DEFS
+const char *vkd3d_test_platform = "other";
+struct vkd3d_test_state vkd3d_test_state;
+
+static void vkd3d_test_main(int argc, char **argv);
+
int main(int argc, char **argv)
{
const char *test_filter = getenv("VKD3D_TEST_FILTER");
@@ -339,6 +345,7 @@ int wmain(int argc, WCHAR **wargv)
return ret;
}
#endif /* _WIN32 */
+#endif /* VKD3D_TEST_NO_DEFS */
typedef void (*vkd3d_test_pfn)(void);
diff --git a/tests/shader_runner.c b/tests/shader_runner.c
new file mode 100644
index 000000000..df4344881
--- /dev/null
+++ b/tests/shader_runner.c
@@ -0,0 +1,862 @@
+/*
+ * Copyright 2020-2021 Zebediah Figura for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/*
+ * This application contains code derived from piglit, the license for which
+ * follows:
+ *
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "d3d12_crosstest.h"
+#include "shader_runner.h"
+#include <errno.h>
+
+static void VKD3D_NORETURN VKD3D_PRINTF_FUNC(1, 2) fatal_error(const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+ exit(1);
+}
+
+static bool vkd3d_array_reserve(void **elements, size_t *capacity, size_t element_count, size_t element_size)
+{
+ size_t new_capacity, max_capacity;
+ void *new_elements;
+
+ if (element_count <= *capacity)
+ return true;
+
+ max_capacity = ~(size_t)0 / element_size;
+ if (max_capacity < element_count)
+ return false;
+
+ new_capacity = max(*capacity, 4);
+ while (new_capacity < element_count && new_capacity <= max_capacity / 2)
+ new_capacity *= 2;
+
+ if (new_capacity < element_count)
+ new_capacity = element_count;
+
+ if (!(new_elements = realloc(*elements, new_capacity * element_size)))
+ return false;
+
+ *elements = new_elements;
+ *capacity = new_capacity;
+
+ return true;
+}
+
+enum texture_data_type
+{
+ TEXTURE_DATA_FLOAT,
+ TEXTURE_DATA_SINT,
+ TEXTURE_DATA_UINT,
+};
+
+struct sampler
+{
+ unsigned int slot;
+
+ D3D12_FILTER filter;
+ D3D12_TEXTURE_ADDRESS_MODE u_address, v_address, w_address;
+};
+
+struct texture
+{
+ unsigned int slot;
+
+ DXGI_FORMAT format;
+ enum texture_data_type data_type;
+ unsigned int texel_size;
+ unsigned int width, height;
+ uint8_t *data;
+ size_t data_size, data_capacity;
+
+ D3D12_DESCRIPTOR_RANGE descriptor_range;
+ ID3D12DescriptorHeap *heap;
+ ID3D12Resource *resource;
+ unsigned int root_index;
+};
+
+struct shader_context
+{
+ const struct shader_runner_ops *ops;
+
+ struct test_context c;
+
+ ID3D10Blob *ps_code;
+
+ uint32_t *uniforms;
+ size_t uniform_count;
+
+ struct texture *textures;
+ size_t texture_count;
+
+ struct sampler *samplers;
+ size_t sampler_count;
+};
+
+static void free_texture(struct texture *texture)
+{
+ ID3D12DescriptorHeap_Release(texture->heap);
+ ID3D12Resource_Release(texture->resource);
+ free(texture->data);
+ memset(texture, 0, sizeof(*texture));
+}
+
+enum parse_state
+{
+ STATE_NONE,
+ STATE_PREPROC,
+ STATE_PREPROC_INVALID,
+ STATE_SAMPLER,
+ STATE_SHADER_INVALID_PIXEL,
+ STATE_SHADER_PIXEL,
+ STATE_TEXTURE,
+ STATE_TEST,
+};
+
+static bool match_string(const char *line, const char *token, const char **const rest)
+{
+ size_t len = strlen(token);
+
+ if (strncmp(line, token, len) || !isspace(line[len]))
+ return false;
+ if (rest)
+ {
+ *rest = line + len;
+ while (isspace(**rest))
+ ++*rest;
+ }
+ return true;
+}
+
+static void parse_texture_format(struct texture *texture, const char *line)
+{
+ static const struct
+ {
+ const char *string;
+ enum texture_data_type data_type;
+ unsigned int texel_size;
+ DXGI_FORMAT format;
+ }
+ formats[] =
+ {
+ {"r32g32b32a32 float", TEXTURE_DATA_FLOAT, 16, DXGI_FORMAT_R32G32B32A32_FLOAT},
+ {"r32g32 uint", TEXTURE_DATA_UINT, 8, DXGI_FORMAT_R32G32_UINT},
+ {"r32 float", TEXTURE_DATA_FLOAT, 4, DXGI_FORMAT_R32_FLOAT},
+ {"r32 sint", TEXTURE_DATA_SINT, 4, DXGI_FORMAT_R32_SINT},
+ };
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(formats); ++i)
+ {
+ if (match_string(line, formats[i].string, &line))
+ {
+ texture->format = formats[i].format;
+ texture->data_type = formats[i].data_type;
+ texture->texel_size = formats[i].texel_size;
+ return;
+ }
+ }
+
+ fatal_error("Unknown format '%s'.\n", line);
+}
+
+static D3D12_TEXTURE_ADDRESS_MODE parse_sampler_address_mode(const char *line, const char **rest)
+{
+ if (match_string(line, "border", rest))
+ return D3D12_TEXTURE_ADDRESS_MODE_BORDER;
+ if (match_string(line, "clamp", rest))
+ return D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
+ if (match_string(line, "mirror_once", rest))
+ return D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE;
+ if (match_string(line, "mirror", rest))
+ return D3D12_TEXTURE_ADDRESS_MODE_MIRROR;
+ if (match_string(line, "wrap", rest))
+ return D3D12_TEXTURE_ADDRESS_MODE_WRAP;
+
+ fatal_error("Unknown sampler address mode '%s'.\n", line);
+}
+
+static void parse_sampler_directive(struct sampler *sampler, const char *line)
+{
+ if (match_string(line, "address", &line))
+ {
+ sampler->u_address = parse_sampler_address_mode(line, &line);
+ sampler->v_address = parse_sampler_address_mode(line, &line);
+ sampler->w_address = parse_sampler_address_mode(line, &line);
+ }
+ else if (match_string(line, "filter", &line))
+ {
+ static const struct
+ {
+ const char *string;
+ D3D12_FILTER filter;
+ }
+ filters[] =
+ {
+ {"point point point", D3D12_FILTER_MIN_MAG_MIP_POINT},
+ {"point point linear", D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR},
+ {"point linear point", D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT},
+ {"point linear linear", D3D12_FILTER_MIN_POINT_MAG_MIP_LINEAR},
+ {"linear point point", D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT},
+ {"linear point linear", D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR},
+ {"linear linear point", D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT},
+ {"linear linear linear", D3D12_FILTER_MIN_MAG_MIP_LINEAR},
+ };
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(filters); ++i)
+ {
+ if (match_string(line, filters[i].string, &line))
+ {
+ sampler->filter = filters[i].filter;
+ return;
+ }
+ }
+
+ fatal_error("Unknown sampler filter '%s'.\n", line);
+ }
+ else
+ {
+ fatal_error("Unknown sampler directive '%s'.\n", line);
+ }
+}
+
+static void parse_texture_directive(struct texture *texture, const char *line)
+{
+ int ret;
+
+ if (match_string(line, "format", &line))
+ {
+ parse_texture_format(texture, line);
+ }
+ else if (match_string(line, "size", &line))
+ {
+ ret = sscanf(line, "( %u , %u )", &texture->width, &texture->height);
+ if (ret < 2)
+ fatal_error("Malformed texture size '%s'.\n", line);
+ }
+ else
+ {
+ union
+ {
+ float f;
+ int32_t i;
+ uint32_t u;
+ } u;
+ char *rest;
+
+ u.u = 0;
+
+ for (;;)
+ {
+ switch (texture->data_type)
+ {
+ case TEXTURE_DATA_FLOAT:
+ u.f = strtof(line, &rest);
+ break;
+
+ case TEXTURE_DATA_SINT:
+ u.i = strtol(line, &rest, 10);
+ break;
+
+ case TEXTURE_DATA_UINT:
+ u.u = strtoul(line, &rest, 10);
+ break;
+ }
+
+ if (rest == line)
+ break;
+
+ vkd3d_array_reserve((void **)&texture->data, &texture->data_capacity, texture->data_size + sizeof(u), 1);
+ memcpy(texture->data + texture->data_size, &u, sizeof(u));
+ texture->data_size += sizeof(u);
+ line = rest;
+ }
+ }
+}
+
+static void parse_test_directive(struct shader_context *context, const char *line)
+{
+ if (match_string(line, "draw quad", &line))
+ {
+ D3D12_SHADER_BYTECODE ps
+ = {ID3D10Blob_GetBufferPointer(context->ps_code), ID3D10Blob_GetBufferSize(context->ps_code)};
+ ID3D12GraphicsCommandList *command_list = context->c.list;
+ D3D12_ROOT_SIGNATURE_DESC root_signature_desc = {0};
+ D3D12_ROOT_PARAMETER root_params[3], *root_param;
+ D3D12_STATIC_SAMPLER_DESC static_samplers[1];
+ static const float clear_color[4];
+ unsigned int uniform_index;
+ ID3D12PipelineState *pso;
+ HRESULT hr;
+ size_t i;
+
+ root_signature_desc.NumParameters = 0;
+ root_signature_desc.pParameters = root_params;
+ root_signature_desc.NumStaticSamplers = 0;
+ root_signature_desc.pStaticSamplers = static_samplers;
+
+ if (context->uniform_count)
+ {
+ uniform_index = root_signature_desc.NumParameters++;
+ root_param = &root_params[uniform_index];
+ root_param->ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
+ root_param->Constants.ShaderRegister = 0;
+ root_param->Constants.RegisterSpace = 0;
+ root_param->Constants.Num32BitValues = context->uniform_count;
+ root_param->ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
+ }
+
+ for (i = 0; i < context->texture_count; ++i)
+ {
+ struct texture *texture = &context->textures[i];
+ D3D12_DESCRIPTOR_RANGE *range = &texture->descriptor_range;
+ D3D12_SUBRESOURCE_DATA resource_data;
+
+ texture->root_index = root_signature_desc.NumParameters++;
+ root_param = &root_params[texture->root_index];
+ root_param->ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
+ root_param->DescriptorTable.NumDescriptorRanges = 1;
+ root_param->DescriptorTable.pDescriptorRanges = range;
+ root_param->ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
+
+ range->RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
+ range->NumDescriptors = 1;
+ range->BaseShaderRegister = texture->slot;
+ range->RegisterSpace = 0;
+ range->OffsetInDescriptorsFromTableStart = 0;
+
+ if (!texture->resource)
+ {
+ texture->heap = create_gpu_descriptor_heap(context->c.device,
+ D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 1);
+ texture->resource = create_default_texture(context->c.device, texture->width, texture->height,
+ texture->format, 0, D3D12_RESOURCE_STATE_COPY_DEST);
+ resource_data.pData = texture->data;
+ resource_data.SlicePitch = resource_data.RowPitch = texture->width * texture->texel_size;
+ upload_texture_data(texture->resource, &resource_data, 1, context->c.queue, command_list);
+ reset_command_list(command_list, context->c.allocator);
+ transition_resource_state(command_list, texture->resource, D3D12_RESOURCE_STATE_COPY_DEST,
+ D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
+ ID3D12Device_CreateShaderResourceView(context->c.device, texture->resource,
+ NULL, get_cpu_descriptor_handle(&context->c, texture->heap, 0));
+ }
+ }
+
+ assert(root_signature_desc.NumParameters <= ARRAY_SIZE(root_params));
+
+ for (i = 0; i < context->sampler_count; ++i)
+ {
+ D3D12_STATIC_SAMPLER_DESC *sampler_desc = &static_samplers[root_signature_desc.NumStaticSamplers++];
+ const struct sampler *sampler = &context->samplers[i];
+
+ memset(sampler_desc, 0, sizeof(*sampler_desc));
+ sampler_desc->Filter = sampler->filter;
+ sampler_desc->AddressU = sampler->u_address;
+ sampler_desc->AddressV = sampler->v_address;
+ sampler_desc->AddressW = sampler->w_address;
+ sampler_desc->ShaderRegister = sampler->slot;
+ sampler_desc->RegisterSpace = 0;
+ sampler_desc->ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
+ }
+
+ if (context->c.root_signature)
+ ID3D12RootSignature_Release(context->c.root_signature);
+ hr = create_root_signature(context->c.device, &root_signature_desc, &context->c.root_signature);
+ ok(hr == S_OK, "Failed to create root signature, hr %#x.\n", hr);
+
+ pso = create_pipeline_state(context->c.device, context->c.root_signature, context->c.render_target_desc.Format,
+ NULL, &ps, NULL);
+ if (!pso)
+ return;
+ vkd3d_array_reserve((void **)&context->c.pso, &context->c.pso_capacity, context->c.pso_count + 1, sizeof(*context->c.pso));
+ context->c.pso[context->c.pso_count++] = pso;
+
+ ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context->c.root_signature);
+ if (context->uniform_count)
+ ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(command_list, uniform_index,
+ context->uniform_count, context->uniforms, 0);
+ for (i = 0; i < context->texture_count; ++i)
+ ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(command_list, context->textures[i].root_index,
+ get_gpu_descriptor_handle(&context->c, context->textures[i].heap, 0));
+
+ ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &context->c.rtv, false, NULL);
+ ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context->c.scissor_rect);
+ ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context->c.viewport);
+ ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+ ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, context->c.rtv, clear_color, 0, NULL);
+ ID3D12GraphicsCommandList_SetPipelineState(command_list, pso);
+ ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 1, 0, 0);
+ transition_resource_state(command_list, context->c.render_target,
+ D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
+ }
+ else if (match_string(line, "probe all rgba", &line))
+ {
+ unsigned int ulps;
+ struct vec4 v;
+ int ret;
+
+ ret = sscanf(line, "( %f , %f , %f , %f ) %u", &v.x, &v.y, &v.z, &v.w, &ulps);
+ if (ret < 4)
+ fatal_error("Malformed probe arguments '%s'.\n", line);
+ if (ret < 5)
+ ulps = 0;
+ check_sub_resource_vec4(context->c.render_target, 0, context->c.queue, context->c.list, &v, ulps);
+ reset_command_list(context->c.list, context->c.allocator);
+ }
+ else if (match_string(line, "probe rect rgba", &line))
+ {
+ unsigned int x, y, w, h, ulps;
+ struct resource_readback rb;
+ struct vec4 v;
+ RECT rect;
+ int ret;
+
+ ret = sscanf(line, "( %u , %u , %u , %u ) ( %f , %f , %f , %f ) %u",
+ &x, &y, &w, &h, &v.x, &v.y, &v.z, &v.w, &ulps);
+ if (ret < 8)
+ fatal_error("Malformed probe arguments '%s'.\n", line);
+ if (ret < 9)
+ ulps = 0;
+
+ get_texture_readback_with_command_list(context->c.render_target, 0, &rb, context->c.queue, context->c.list);
+ rect.left = x;
+ rect.right = x + w;
+ rect.top = y;
+ rect.bottom = y + h;
+ check_readback_data_vec4(&rb, &rect, &v, ulps);
+ release_resource_readback(&rb);
+ reset_command_list(context->c.list, context->c.allocator);
+ }
+ else if (match_string(line, "probe rgba", &line))
+ {
+ struct resource_readback rb;
+ unsigned int x, y, ulps;
+ struct vec4 v;
+ RECT rect;
+ int ret;
+
+ ret = sscanf(line, "( %u , %u ) ( %f , %f , %f , %f ) %u", &x, &y, &v.x, &v.y, &v.z, &v.w, &ulps);
+ if (ret < 6)
+ fatal_error("Malformed probe arguments '%s'.\n", line);
+ if (ret < 7)
+ ulps = 0;
+
+ get_texture_readback_with_command_list(context->c.render_target, 0, &rb, context->c.queue, context->c.list);
+ rect.left = x;
+ rect.right = x + 1;
+ rect.top = y;
+ rect.bottom = y + 1;
+ check_readback_data_vec4(&rb, &rect, &v, ulps);
+ release_resource_readback(&rb);
+ reset_command_list(context->c.list, context->c.allocator);
+ }
+ else if (match_string(line, "uniform", &line))
+ {
+ unsigned int offset;
+
+ if (!sscanf(line, "%u", &offset))
+ fatal_error("Unknown uniform type '%s'.\n", line);
+ line = strchr(line, ' ') + 1;
+
+ if (match_string(line, "float4", &line))
+ {
+ struct vec4 v;
+
+ if (sscanf(line, "%f %f %f %f", &v.x, &v.y, &v.z, &v.w) < 4)
+ fatal_error("Malformed float4 constant '%s'.\n", line);
+ if (offset + 4 > context->uniform_count)
+ {
+ context->uniform_count = offset + 4;
+ context->uniforms = realloc(context->uniforms, context->uniform_count * sizeof(*context->uniforms));
+ }
+ memcpy(context->uniforms + offset, &v, sizeof(v));
+ }
+ else if (match_string(line, "float", &line))
+ {
+ float f;
+
+ if (sscanf(line, "%f", &f) < 1)
+ fatal_error("Malformed float constant '%s'.\n", line);
+ if (offset + 1 > context->uniform_count)
+ {
+ context->uniform_count = offset + 1;
+ context->uniforms = realloc(context->uniforms, context->uniform_count * sizeof(*context->uniforms));
+ }
+ memcpy(context->uniforms + offset, &f, sizeof(f));
+ }
+ else if (match_string(line, "int", &line))
+ {
+ int i;
+
+ if (sscanf(line, "%i", &i) < 1)
+ fatal_error("Malformed int constant '%s'.\n", line);
+ if (offset + 1 > context->uniform_count)
+ {
+ context->uniform_count = offset + 1;
+ context->uniforms = realloc(context->uniforms, context->uniform_count * sizeof(*context->uniforms));
+ }
+ memcpy(context->uniforms + offset, &i, sizeof(i));
+ }
+ else if (match_string(line, "uint", &line))
+ {
+ unsigned int u;
+
+ if (sscanf(line, "%u", &u) < 1)
+ fatal_error("Malformed uint constant '%s'.\n", line);
+ if (offset + 1 > context->uniform_count)
+ {
+ context->uniform_count = offset + 1;
+ context->uniforms = realloc(context->uniforms, context->uniform_count * sizeof(*context->uniforms));
+ }
+ memcpy(context->uniforms + offset, &u, sizeof(u));
+ }
+ }
+ else
+ {
+ fatal_error("Unknown test directive '%s'.\n", line);
+ }
+}
+
+static struct sampler *get_sampler(struct shader_context *context, unsigned int slot)
+{
+ struct sampler *sampler;
+ size_t i;
+
+ for (i = 0; i < context->sampler_count; ++i)
+ {
+ sampler = &context->samplers[i];
+
+ if (sampler->slot == slot)
+ return sampler;
+ }
+
+ return NULL;
+}
+
+static struct texture *get_texture(struct shader_context *context, unsigned int slot)
+{
+ struct texture *texture;
+ size_t i;
+
+ for (i = 0; i < context->texture_count; ++i)
+ {
+ texture = &context->textures[i];
+ if (texture->slot == slot)
+ return texture;
+ }
+
+ return NULL;
+}
+
+void run_shader_tests(int argc, char **argv, const struct shader_runner_ops *ops)
+{
+ static const struct test_context_desc desc =
+ {
+ .rt_width = 640,
+ .rt_height = 480,
+ .no_root_signature = true,
+ .rt_format = DXGI_FORMAT_R32G32B32A32_FLOAT,
+ };
+ size_t shader_source_size = 0, shader_source_len = 0;
+ struct sampler *current_sampler = NULL;
+ struct texture *current_texture = NULL;
+ enum parse_state state = STATE_NONE;
+ unsigned int i, line_number = 0;
+ struct shader_context context;
+ const char *filename = NULL;
+ char *shader_source = NULL;
+ char line[256];
+ FILE *f;
+
+ parse_args(argc, argv);
+ enable_d3d12_debug_layer(argc, argv);
+ init_adapter_info();
+
+ for (i = 1; i < argc; ++i)
+ {
+ if (argv[i][0] != '-')
+ {
+ filename = argv[i];
+ break;
+ }
+ }
+
+ if (!filename)
+ {
+ fprintf(stderr, "Usage: %s [file]\n", argv[0]);
+ return;
+ }
+
+ if (!(f = fopen(filename, "r")))
+ {
+ fatal_error("Unable to open '%s' for reading: %s\n", argv[1], strerror(errno));
+ return;
+ }
+
+ memset(&context, 0, sizeof(context));
+ context.ops = ops;
+ init_test_context(&context.c, &desc);
+
+ for (;;)
+ {
+ char *ret = fgets(line, sizeof(line), f);
+
+ ++line_number;
+
+ if (!ret || line[0] == '[')
+ {
+ switch (state)
+ {
+ case STATE_NONE:
+ case STATE_SAMPLER:
+ case STATE_TEST:
+ case STATE_TEXTURE:
+ break;
+
+ case STATE_SHADER_PIXEL:
+ if (!(context.ps_code = context.ops->compile_shader(shader_source)))
+ return;
+ shader_source_len = 0;
+ break;
+
+ case STATE_SHADER_INVALID_PIXEL:
+ {
+ ID3D10Blob *blob = NULL, *errors = NULL;
+ HRESULT hr;
+
+ hr = D3DCompile(shader_source, strlen(shader_source), NULL,
+ NULL, NULL, "main", "ps_4_0", 0, 0, &blob, &errors);
+ ok(hr == E_FAIL, "Got unexpected hr %#x.\n", hr);
+ ok(!blob, "Expected no compiled shader blob.\n");
+ ok(!!errors, "Expected non-NULL error blob.\n");
+ if (!errors)
+ return;
+
+ if (vkd3d_test_state.debug_level)
+ trace("%s\n", (char *)ID3D10Blob_GetBufferPointer(errors));
+ ID3D10Blob_Release(errors);
+
+ shader_source_len = 0;
+ break;
+ }
+
+ case STATE_PREPROC_INVALID:
+ {
+ ID3D10Blob *blob = NULL, *errors = NULL;
+ HRESULT hr;
+
+ hr = D3DPreprocess(shader_source, strlen(shader_source), NULL, NULL, NULL, &blob, &errors);
+ ok(hr == E_FAIL, "Got unexpected hr %#x.\n", hr);
+ ok(!blob, "Expected no compiled shader blob.\n");
+ ok(!!errors, "Expected non-NULL error blob.\n");
+
+ if (errors)
+ {
+ if (vkd3d_test_state.debug_level)
+ trace("%s\n", (char *)ID3D10Blob_GetBufferPointer(errors));
+ ID3D10Blob_Release(errors);
+ }
+
+ shader_source_len = 0;
+ break;
+ }
+
+ case STATE_PREPROC:
+ {
+ ID3D10Blob *blob = NULL, *errors = NULL;
+ SIZE_T size;
+ HRESULT hr;
+ char *text;
+
+ hr = D3DPreprocess(shader_source, strlen(shader_source), NULL, NULL, NULL, &blob, &errors);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ if (hr == S_OK)
+ {
+ if (errors)
+ {
+ if (vkd3d_test_state.debug_level)
+ trace("%s\n", (char *)ID3D10Blob_GetBufferPointer(errors));
+ ID3D10Blob_Release(errors);
+ }
+
+ text = ID3D10Blob_GetBufferPointer(blob);
+ size = ID3D10Blob_GetBufferSize(blob);
+ ok(vkd3d_memmem(text, size, "pass", strlen("pass")),
+ "'pass' not found in preprocessed shader.\n");
+ ok(!vkd3d_memmem(text, size, "fail", strlen("fail")),
+ "'fail' found in preprocessed shader.\n");
+ ID3D10Blob_Release(blob);
+ }
+
+ shader_source_len = 0;
+ break;
+ }
+ }
+ }
+
+ if (!ret)
+ break;
+
+ if (line[0] == '[')
+ {
+ unsigned int index;
+
+ if (!strcmp(line, "[pixel shader]\n"))
+ {
+ state = STATE_SHADER_PIXEL;
+
+ if (context.ps_code)
+ ID3D10Blob_Release(context.ps_code);
+ context.ps_code = NULL;
+ }
+ else if (!strcmp(line, "[pixel shader fail]\n"))
+ {
+ state = STATE_SHADER_INVALID_PIXEL;
+ }
+ else if (sscanf(line, "[sampler %u]\n", &index))
+ {
+ state = STATE_SAMPLER;
+
+ if ((current_sampler = get_sampler(&context, index)))
+ {
+ memset(current_sampler, 0, sizeof(*current_sampler));
+ }
+ else
+ {
+ context.samplers = realloc(context.samplers,
+ ++context.sampler_count * sizeof(*context.samplers));
+ current_sampler = &context.samplers[context.sampler_count - 1];
+ memset(current_sampler, 0, sizeof(*current_sampler));
+ }
+ current_sampler->slot = index;
+ current_sampler->filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
+ current_sampler->u_address = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
+ current_sampler->v_address = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
+ current_sampler->w_address = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
+ }
+ else if (sscanf(line, "[texture %u]\n", &index))
+ {
+ state = STATE_TEXTURE;
+
+ if ((current_texture = get_texture(&context, index)))
+ {
+ free_texture(current_texture);
+ }
+ else
+ {
+ context.textures = realloc(context.textures,
+ ++context.texture_count * sizeof(*context.textures));
+ current_texture = &context.textures[context.texture_count - 1];
+ memset(current_texture, 0, sizeof(*current_texture));
+ }
+ current_texture->slot = index;
+ current_texture->format = DXGI_FORMAT_R32G32B32A32_FLOAT;
+ current_texture->data_type = TEXTURE_DATA_FLOAT;
+ current_texture->texel_size = 16;
+ }
+ else if (!strcmp(line, "[test]\n"))
+ {
+ state = STATE_TEST;
+ }
+ else if (!strcmp(line, "[preproc]\n"))
+ {
+ state = STATE_PREPROC;
+ }
+ else if (!strcmp(line, "[preproc fail]\n"))
+ {
+ state = STATE_PREPROC_INVALID;
+ }
+
+ vkd3d_test_set_context("Section %.*s, line %u", strlen(line) - 1, line, line_number);
+ }
+ else if (line[0] != '%' && line[0] != '\n')
+ {
+ switch (state)
+ {
+ case STATE_NONE:
+ fatal_error("Malformed line '%s'.\n", line);
+ break;
+
+ case STATE_PREPROC:
+ case STATE_PREPROC_INVALID:
+ case STATE_SHADER_INVALID_PIXEL:
+ case STATE_SHADER_PIXEL:
+ {
+ size_t len = strlen(line);
+
+ vkd3d_array_reserve((void **)&shader_source, &shader_source_size, shader_source_len + len + 1, 1);
+ memcpy(shader_source + shader_source_len, line, len + 1);
+ shader_source_len += len;
+ break;
+ }
+
+ case STATE_SAMPLER:
+ parse_sampler_directive(current_sampler, line);
+ break;
+
+ case STATE_TEXTURE:
+ parse_texture_directive(current_texture, line);
+ break;
+
+ case STATE_TEST:
+ parse_test_directive(&context, line);
+ break;
+ }
+ }
+ }
+
+ if (context.ps_code)
+ ID3D10Blob_Release(context.ps_code);
+ for (i = 0; i < context.texture_count; ++i)
+ free_texture(&context.textures[i]);
+ destroy_test_context(&context.c);
+
+ fclose(f);
+}
+
+START_TEST(shader_runner)
+{
+ run_shader_tests_d3d12(argc, argv);
+}
diff --git a/tests/shader_runner.h b/tests/shader_runner.h
new file mode 100644
index 000000000..5178c6544
--- /dev/null
+++ b/tests/shader_runner.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2021 Zebediah Figura for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "vkd3d_windows.h"
+#include "vkd3d_d3dcommon.h"
+
+struct shader_runner_ops
+{
+ ID3D10Blob *(*compile_shader)(const char *source);
+};
+
+void run_shader_tests(int argc, char **argv, const struct shader_runner_ops *ops);
+
+void run_shader_tests_d3d12(int argc, char **argv);
diff --git a/tests/shader_runner_d3d12.c b/tests/shader_runner_d3d12.c
index 47f419b96..6246c8701 100644
--- a/tests/shader_runner_d3d12.c
+++ b/tests/shader_runner_d3d12.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 Zebediah Figura for CodeWeavers
+ * Copyright 2020-2021 Zebediah Figura for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -16,127 +16,21 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
-/*
- * This application contains code derived from piglit, the license for which
- * follows:
- *
- * Copyright © 2010 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#include "d3d12_crosstest.h"
-#include <errno.h>
-
-static void VKD3D_NORETURN VKD3D_PRINTF_FUNC(1, 2) fatal_error(const char *format, ...)
-{
- va_list args;
-
- va_start(args, format);
- vfprintf(stderr, format, args);
- va_end(args);
- exit(1);
-}
-
-static bool vkd3d_array_reserve(void **elements, size_t *capacity, size_t element_count, size_t element_size)
-{
- size_t new_capacity, max_capacity;
- void *new_elements;
-
- if (element_count <= *capacity)
- return true;
-
- max_capacity = ~(size_t)0 / element_size;
- if (max_capacity < element_count)
- return false;
-
- new_capacity = max(*capacity, 4);
- while (new_capacity < element_count && new_capacity <= max_capacity / 2)
- new_capacity *= 2;
-
- if (new_capacity < element_count)
- new_capacity = element_count;
-
- if (!(new_elements = realloc(*elements, new_capacity * element_size)))
- return false;
-
- *elements = new_elements;
- *capacity = new_capacity;
-
- return true;
-}
-
-enum texture_data_type
-{
- TEXTURE_DATA_FLOAT,
- TEXTURE_DATA_SINT,
- TEXTURE_DATA_UINT,
-};
+#define COBJMACROS
+#define CONST_VTABLE
+#define VKD3D_TEST_NO_DEFS
+#include "vkd3d_windows.h"
+#include "vkd3d_d3dcommon.h"
+#include "vkd3d_d3dcompiler.h"
+#include "vkd3d_test.h"
+#include "shader_runner.h"
-struct sampler
-{
- unsigned int slot;
-
- D3D12_FILTER filter;
- D3D12_TEXTURE_ADDRESS_MODE u_address, v_address, w_address;
-};
-
-struct texture
-{
- unsigned int slot;
-
- DXGI_FORMAT format;
- enum texture_data_type data_type;
- unsigned int texel_size;
- unsigned int width, height;
- uint8_t *data;
- size_t data_size, data_capacity;
-
- D3D12_DESCRIPTOR_RANGE descriptor_range;
- ID3D12DescriptorHeap *heap;
- ID3D12Resource *resource;
- unsigned int root_index;
-};
-
-struct shader_context
-{
- struct test_context c;
-
- ID3D10Blob *ps_code;
-
- uint32_t *uniforms;
- size_t uniform_count;
-
- struct texture *textures;
- size_t texture_count;
-
- struct sampler *samplers;
- size_t sampler_count;
-};
-
-static ID3D10Blob *compile_shader(const char *source, const char *target)
+static ID3D10Blob *d3d12_runner_compile_shader(const char *source)
{
ID3D10Blob *blob = NULL, *errors = NULL;
HRESULT hr;
- hr = D3DCompile(source, strlen(source), NULL, NULL, NULL, "main", target, 0, 0, &blob, &errors);
+ hr = D3DCompile(source, strlen(source), NULL, NULL, NULL, "main", "ps_4_0", 0, 0, &blob, &errors);
ok(hr == S_OK, "Failed to compile shader, hr %#x.\n", hr);
if (errors)
{
@@ -147,723 +41,12 @@ static ID3D10Blob *compile_shader(const char *source, const char *target)
return blob;
}
-static void free_texture(struct texture *texture)
+static const struct shader_runner_ops d3d12_runner_ops =
{
- ID3D12DescriptorHeap_Release(texture->heap);
- ID3D12Resource_Release(texture->resource);
- free(texture->data);
- memset(texture, 0, sizeof(*texture));
-}
-
-enum parse_state
-{
- STATE_NONE,
- STATE_PREPROC,
- STATE_PREPROC_INVALID,
- STATE_SAMPLER,
- STATE_SHADER_INVALID_PIXEL,
- STATE_SHADER_PIXEL,
- STATE_TEXTURE,
- STATE_TEST,
+ .compile_shader = d3d12_runner_compile_shader,
};
-static bool match_string(const char *line, const char *token, const char **const rest)
-{
- size_t len = strlen(token);
-
- if (strncmp(line, token, len) || !isspace(line[len]))
- return false;
- if (rest)
- {
- *rest = line + len;
- while (isspace(**rest))
- ++*rest;
- }
- return true;
-}
-
-static void parse_texture_format(struct texture *texture, const char *line)
-{
- static const struct
- {
- const char *string;
- enum texture_data_type data_type;
- unsigned int texel_size;
- DXGI_FORMAT format;
- }
- formats[] =
- {
- {"r32g32b32a32 float", TEXTURE_DATA_FLOAT, 16, DXGI_FORMAT_R32G32B32A32_FLOAT},
- {"r32g32 uint", TEXTURE_DATA_UINT, 8, DXGI_FORMAT_R32G32_UINT},
- {"r32 float", TEXTURE_DATA_FLOAT, 4, DXGI_FORMAT_R32_FLOAT},
- {"r32 sint", TEXTURE_DATA_SINT, 4, DXGI_FORMAT_R32_SINT},
- };
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(formats); ++i)
- {
- if (match_string(line, formats[i].string, &line))
- {
- texture->format = formats[i].format;
- texture->data_type = formats[i].data_type;
- texture->texel_size = formats[i].texel_size;
- return;
- }
- }
-
- fatal_error("Unknown format '%s'.\n", line);
-}
-
-static D3D12_TEXTURE_ADDRESS_MODE parse_sampler_address_mode(const char *line, const char **rest)
-{
- if (match_string(line, "border", rest))
- return D3D12_TEXTURE_ADDRESS_MODE_BORDER;
- if (match_string(line, "clamp", rest))
- return D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
- if (match_string(line, "mirror_once", rest))
- return D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE;
- if (match_string(line, "mirror", rest))
- return D3D12_TEXTURE_ADDRESS_MODE_MIRROR;
- if (match_string(line, "wrap", rest))
- return D3D12_TEXTURE_ADDRESS_MODE_WRAP;
-
- fatal_error("Unknown sampler address mode '%s'.\n", line);
-}
-
-static void parse_sampler_directive(struct sampler *sampler, const char *line)
-{
- if (match_string(line, "address", &line))
- {
- sampler->u_address = parse_sampler_address_mode(line, &line);
- sampler->v_address = parse_sampler_address_mode(line, &line);
- sampler->w_address = parse_sampler_address_mode(line, &line);
- }
- else if (match_string(line, "filter", &line))
- {
- static const struct
- {
- const char *string;
- D3D12_FILTER filter;
- }
- filters[] =
- {
- {"point point point", D3D12_FILTER_MIN_MAG_MIP_POINT},
- {"point point linear", D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR},
- {"point linear point", D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT},
- {"point linear linear", D3D12_FILTER_MIN_POINT_MAG_MIP_LINEAR},
- {"linear point point", D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT},
- {"linear point linear", D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR},
- {"linear linear point", D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT},
- {"linear linear linear", D3D12_FILTER_MIN_MAG_MIP_LINEAR},
- };
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(filters); ++i)
- {
- if (match_string(line, filters[i].string, &line))
- {
- sampler->filter = filters[i].filter;
- return;
- }
- }
-
- fatal_error("Unknown sampler filter '%s'.\n", line);
- }
- else
- {
- fatal_error("Unknown sampler directive '%s'.\n", line);
- }
-}
-
-static void parse_texture_directive(struct texture *texture, const char *line)
-{
- int ret;
-
- if (match_string(line, "format", &line))
- {
- parse_texture_format(texture, line);
- }
- else if (match_string(line, "size", &line))
- {
- ret = sscanf(line, "( %u , %u )", &texture->width, &texture->height);
- if (ret < 2)
- fatal_error("Malformed texture size '%s'.\n", line);
- }
- else
- {
- union
- {
- float f;
- int32_t i;
- uint32_t u;
- } u;
- char *rest;
-
- u.u = 0;
-
- for (;;)
- {
- switch (texture->data_type)
- {
- case TEXTURE_DATA_FLOAT:
- u.f = strtof(line, &rest);
- break;
-
- case TEXTURE_DATA_SINT:
- u.i = strtol(line, &rest, 10);
- break;
-
- case TEXTURE_DATA_UINT:
- u.u = strtoul(line, &rest, 10);
- break;
- }
-
- if (rest == line)
- break;
-
- vkd3d_array_reserve((void **)&texture->data, &texture->data_capacity, texture->data_size + sizeof(u), 1);
- memcpy(texture->data + texture->data_size, &u, sizeof(u));
- texture->data_size += sizeof(u);
- line = rest;
- }
- }
-}
-
-static void parse_test_directive(struct shader_context *context, const char *line)
-{
- if (match_string(line, "draw quad", &line))
- {
- D3D12_SHADER_BYTECODE ps
- = {ID3D10Blob_GetBufferPointer(context->ps_code), ID3D10Blob_GetBufferSize(context->ps_code)};
- ID3D12GraphicsCommandList *command_list = context->c.list;
- D3D12_ROOT_SIGNATURE_DESC root_signature_desc = {0};
- D3D12_ROOT_PARAMETER root_params[3], *root_param;
- D3D12_STATIC_SAMPLER_DESC static_samplers[1];
- static const float clear_color[4];
- unsigned int uniform_index;
- ID3D12PipelineState *pso;
- HRESULT hr;
- size_t i;
-
- root_signature_desc.NumParameters = 0;
- root_signature_desc.pParameters = root_params;
- root_signature_desc.NumStaticSamplers = 0;
- root_signature_desc.pStaticSamplers = static_samplers;
-
- if (context->uniform_count)
- {
- uniform_index = root_signature_desc.NumParameters++;
- root_param = &root_params[uniform_index];
- root_param->ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
- root_param->Constants.ShaderRegister = 0;
- root_param->Constants.RegisterSpace = 0;
- root_param->Constants.Num32BitValues = context->uniform_count;
- root_param->ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
- }
-
- for (i = 0; i < context->texture_count; ++i)
- {
- struct texture *texture = &context->textures[i];
- D3D12_DESCRIPTOR_RANGE *range = &texture->descriptor_range;
- D3D12_SUBRESOURCE_DATA resource_data;
-
- texture->root_index = root_signature_desc.NumParameters++;
- root_param = &root_params[texture->root_index];
- root_param->ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
- root_param->DescriptorTable.NumDescriptorRanges = 1;
- root_param->DescriptorTable.pDescriptorRanges = range;
- root_param->ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
-
- range->RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
- range->NumDescriptors = 1;
- range->BaseShaderRegister = texture->slot;
- range->RegisterSpace = 0;
- range->OffsetInDescriptorsFromTableStart = 0;
-
- if (!texture->resource)
- {
- texture->heap = create_gpu_descriptor_heap(context->c.device,
- D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 1);
- texture->resource = create_default_texture(context->c.device, texture->width, texture->height,
- texture->format, 0, D3D12_RESOURCE_STATE_COPY_DEST);
- resource_data.pData = texture->data;
- resource_data.SlicePitch = resource_data.RowPitch = texture->width * texture->texel_size;
- upload_texture_data(texture->resource, &resource_data, 1, context->c.queue, command_list);
- reset_command_list(command_list, context->c.allocator);
- transition_resource_state(command_list, texture->resource, D3D12_RESOURCE_STATE_COPY_DEST,
- D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
- ID3D12Device_CreateShaderResourceView(context->c.device, texture->resource,
- NULL, get_cpu_descriptor_handle(&context->c, texture->heap, 0));
- }
- }
-
- assert(root_signature_desc.NumParameters <= ARRAY_SIZE(root_params));
-
- for (i = 0; i < context->sampler_count; ++i)
- {
- D3D12_STATIC_SAMPLER_DESC *sampler_desc = &static_samplers[root_signature_desc.NumStaticSamplers++];
- const struct sampler *sampler = &context->samplers[i];
-
- memset(sampler_desc, 0, sizeof(*sampler_desc));
- sampler_desc->Filter = sampler->filter;
- sampler_desc->AddressU = sampler->u_address;
- sampler_desc->AddressV = sampler->v_address;
- sampler_desc->AddressW = sampler->w_address;
- sampler_desc->ShaderRegister = sampler->slot;
- sampler_desc->RegisterSpace = 0;
- sampler_desc->ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
- }
-
- if (context->c.root_signature)
- ID3D12RootSignature_Release(context->c.root_signature);
- hr = create_root_signature(context->c.device, &root_signature_desc, &context->c.root_signature);
- ok(hr == S_OK, "Failed to create root signature, hr %#x.\n", hr);
-
- pso = create_pipeline_state(context->c.device, context->c.root_signature, context->c.render_target_desc.Format,
- NULL, &ps, NULL);
- if (!pso)
- return;
- vkd3d_array_reserve((void **)&context->c.pso, &context->c.pso_capacity, context->c.pso_count + 1, sizeof(*context->c.pso));
- context->c.pso[context->c.pso_count++] = pso;
-
- ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context->c.root_signature);
- if (context->uniform_count)
- ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(command_list, uniform_index,
- context->uniform_count, context->uniforms, 0);
- for (i = 0; i < context->texture_count; ++i)
- ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(command_list, context->textures[i].root_index,
- get_gpu_descriptor_handle(&context->c, context->textures[i].heap, 0));
-
- ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &context->c.rtv, false, NULL);
- ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context->c.scissor_rect);
- ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context->c.viewport);
- ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
- ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, context->c.rtv, clear_color, 0, NULL);
- ID3D12GraphicsCommandList_SetPipelineState(command_list, pso);
- ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 1, 0, 0);
- transition_resource_state(command_list, context->c.render_target,
- D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
- }
- else if (match_string(line, "probe all rgba", &line))
- {
- unsigned int ulps;
- struct vec4 v;
- int ret;
-
- ret = sscanf(line, "( %f , %f , %f , %f ) %u", &v.x, &v.y, &v.z, &v.w, &ulps);
- if (ret < 4)
- fatal_error("Malformed probe arguments '%s'.\n", line);
- if (ret < 5)
- ulps = 0;
- check_sub_resource_vec4(context->c.render_target, 0, context->c.queue, context->c.list, &v, ulps);
- reset_command_list(context->c.list, context->c.allocator);
- }
- else if (match_string(line, "probe rect rgba", &line))
- {
- unsigned int x, y, w, h, ulps;
- struct resource_readback rb;
- struct vec4 v;
- RECT rect;
- int ret;
-
- ret = sscanf(line, "( %u , %u , %u , %u ) ( %f , %f , %f , %f ) %u",
- &x, &y, &w, &h, &v.x, &v.y, &v.z, &v.w, &ulps);
- if (ret < 8)
- fatal_error("Malformed probe arguments '%s'.\n", line);
- if (ret < 9)
- ulps = 0;
-
- get_texture_readback_with_command_list(context->c.render_target, 0, &rb, context->c.queue, context->c.list);
- rect.left = x;
- rect.right = x + w;
- rect.top = y;
- rect.bottom = y + h;
- check_readback_data_vec4(&rb, &rect, &v, ulps);
- release_resource_readback(&rb);
- reset_command_list(context->c.list, context->c.allocator);
- }
- else if (match_string(line, "probe rgba", &line))
- {
- struct resource_readback rb;
- unsigned int x, y, ulps;
- struct vec4 v;
- RECT rect;
- int ret;
-
- ret = sscanf(line, "( %u , %u ) ( %f , %f , %f , %f ) %u", &x, &y, &v.x, &v.y, &v.z, &v.w, &ulps);
- if (ret < 6)
- fatal_error("Malformed probe arguments '%s'.\n", line);
- if (ret < 7)
- ulps = 0;
-
- get_texture_readback_with_command_list(context->c.render_target, 0, &rb, context->c.queue, context->c.list);
- rect.left = x;
- rect.right = x + 1;
- rect.top = y;
- rect.bottom = y + 1;
- check_readback_data_vec4(&rb, &rect, &v, ulps);
- release_resource_readback(&rb);
- reset_command_list(context->c.list, context->c.allocator);
- }
- else if (match_string(line, "uniform", &line))
- {
- unsigned int offset;
-
- if (!sscanf(line, "%u", &offset))
- fatal_error("Unknown uniform type '%s'.\n", line);
- line = strchr(line, ' ') + 1;
-
- if (match_string(line, "float4", &line))
- {
- struct vec4 v;
-
- if (sscanf(line, "%f %f %f %f", &v.x, &v.y, &v.z, &v.w) < 4)
- fatal_error("Malformed float4 constant '%s'.\n", line);
- if (offset + 4 > context->uniform_count)
- {
- context->uniform_count = offset + 4;
- context->uniforms = realloc(context->uniforms, context->uniform_count * sizeof(*context->uniforms));
- }
- memcpy(context->uniforms + offset, &v, sizeof(v));
- }
- else if (match_string(line, "float", &line))
- {
- float f;
-
- if (sscanf(line, "%f", &f) < 1)
- fatal_error("Malformed float constant '%s'.\n", line);
- if (offset + 1 > context->uniform_count)
- {
- context->uniform_count = offset + 1;
- context->uniforms = realloc(context->uniforms, context->uniform_count * sizeof(*context->uniforms));
- }
- memcpy(context->uniforms + offset, &f, sizeof(f));
- }
- else if (match_string(line, "int", &line))
- {
- int i;
-
- if (sscanf(line, "%i", &i) < 1)
- fatal_error("Malformed int constant '%s'.\n", line);
- if (offset + 1 > context->uniform_count)
- {
- context->uniform_count = offset + 1;
- context->uniforms = realloc(context->uniforms, context->uniform_count * sizeof(*context->uniforms));
- }
- memcpy(context->uniforms + offset, &i, sizeof(i));
- }
- else if (match_string(line, "uint", &line))
- {
- unsigned int u;
-
- if (sscanf(line, "%u", &u) < 1)
- fatal_error("Malformed uint constant '%s'.\n", line);
- if (offset + 1 > context->uniform_count)
- {
- context->uniform_count = offset + 1;
- context->uniforms = realloc(context->uniforms, context->uniform_count * sizeof(*context->uniforms));
- }
- memcpy(context->uniforms + offset, &u, sizeof(u));
- }
- }
- else
- {
- fatal_error("Unknown test directive '%s'.\n", line);
- }
-}
-
-static struct sampler *get_sampler(struct shader_context *context, unsigned int slot)
-{
- struct sampler *sampler;
- size_t i;
-
- for (i = 0; i < context->sampler_count; ++i)
- {
- sampler = &context->samplers[i];
-
- if (sampler->slot == slot)
- return sampler;
- }
-
- return NULL;
-}
-
-static struct texture *get_texture(struct shader_context *context, unsigned int slot)
-{
- struct texture *texture;
- size_t i;
-
- for (i = 0; i < context->texture_count; ++i)
- {
- texture = &context->textures[i];
- if (texture->slot == slot)
- return texture;
- }
-
- return NULL;
-}
-
-START_TEST(shader_runner_d3d12)
+void run_shader_tests_d3d12(int argc, char **argv)
{
- static const struct test_context_desc desc =
- {
- .rt_width = 640,
- .rt_height = 480,
- .no_root_signature = true,
- .rt_format = DXGI_FORMAT_R32G32B32A32_FLOAT,
- };
- size_t shader_source_size = 0, shader_source_len = 0;
- struct sampler *current_sampler = NULL;
- struct texture *current_texture = NULL;
- enum parse_state state = STATE_NONE;
- unsigned int i, line_number = 0;
- struct shader_context context;
- const char *filename = NULL;
- char *shader_source = NULL;
- char line[256];
- FILE *f;
-
- parse_args(argc, argv);
- enable_d3d12_debug_layer(argc, argv);
- init_adapter_info();
-
- for (i = 1; i < argc; ++i)
- {
- if (argv[i][0] != '-')
- {
- filename = argv[i];
- break;
- }
- }
-
- if (!filename)
- {
- fprintf(stderr, "Usage: %s [file]\n", argv[0]);
- return;
- }
-
- if (!(f = fopen(filename, "r")))
- {
- fatal_error("Unable to open '%s' for reading: %s\n", argv[1], strerror(errno));
- return;
- }
-
- memset(&context, 0, sizeof(context));
- init_test_context(&context.c, &desc);
-
- for (;;)
- {
- char *ret = fgets(line, sizeof(line), f);
-
- ++line_number;
-
- if (!ret || line[0] == '[')
- {
- switch (state)
- {
- case STATE_NONE:
- case STATE_SAMPLER:
- case STATE_TEST:
- case STATE_TEXTURE:
- break;
-
- case STATE_SHADER_PIXEL:
- if (!(context.ps_code = compile_shader(shader_source, "ps_4_0")))
- return;
- shader_source_len = 0;
- break;
-
- case STATE_SHADER_INVALID_PIXEL:
- {
- ID3D10Blob *blob = NULL, *errors = NULL;
- HRESULT hr;
-
- hr = D3DCompile(shader_source, strlen(shader_source), NULL,
- NULL, NULL, "main", "ps_4_0", 0, 0, &blob, &errors);
- ok(hr == E_FAIL, "Got unexpected hr %#x.\n", hr);
- ok(!blob, "Expected no compiled shader blob.\n");
- ok(!!errors, "Expected non-NULL error blob.\n");
- if (!errors)
- return;
-
- if (vkd3d_test_state.debug_level)
- trace("%s\n", (char *)ID3D10Blob_GetBufferPointer(errors));
- ID3D10Blob_Release(errors);
-
- shader_source_len = 0;
- break;
- }
-
- case STATE_PREPROC_INVALID:
- {
- ID3D10Blob *blob = NULL, *errors = NULL;
- HRESULT hr;
-
- hr = D3DPreprocess(shader_source, strlen(shader_source), NULL, NULL, NULL, &blob, &errors);
- ok(hr == E_FAIL, "Got unexpected hr %#x.\n", hr);
- ok(!blob, "Expected no compiled shader blob.\n");
- ok(!!errors, "Expected non-NULL error blob.\n");
-
- if (errors)
- {
- if (vkd3d_test_state.debug_level)
- trace("%s\n", (char *)ID3D10Blob_GetBufferPointer(errors));
- ID3D10Blob_Release(errors);
- }
-
- shader_source_len = 0;
- break;
- }
-
- case STATE_PREPROC:
- {
- ID3D10Blob *blob = NULL, *errors = NULL;
- SIZE_T size;
- HRESULT hr;
- char *text;
-
- hr = D3DPreprocess(shader_source, strlen(shader_source), NULL, NULL, NULL, &blob, &errors);
- ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
- if (hr == S_OK)
- {
- if (errors)
- {
- if (vkd3d_test_state.debug_level)
- trace("%s\n", (char *)ID3D10Blob_GetBufferPointer(errors));
- ID3D10Blob_Release(errors);
- }
-
- text = ID3D10Blob_GetBufferPointer(blob);
- size = ID3D10Blob_GetBufferSize(blob);
- ok(vkd3d_memmem(text, size, "pass", strlen("pass")),
- "'pass' not found in preprocessed shader.\n");
- ok(!vkd3d_memmem(text, size, "fail", strlen("fail")),
- "'fail' found in preprocessed shader.\n");
- ID3D10Blob_Release(blob);
- }
-
- shader_source_len = 0;
- break;
- }
- }
- }
-
- if (!ret)
- break;
-
- if (line[0] == '[')
- {
- unsigned int index;
-
- if (!strcmp(line, "[pixel shader]\n"))
- {
- state = STATE_SHADER_PIXEL;
-
- if (context.ps_code)
- ID3D10Blob_Release(context.ps_code);
- context.ps_code = NULL;
- }
- else if (!strcmp(line, "[pixel shader fail]\n"))
- {
- state = STATE_SHADER_INVALID_PIXEL;
- }
- else if (sscanf(line, "[sampler %u]\n", &index))
- {
- state = STATE_SAMPLER;
-
- if ((current_sampler = get_sampler(&context, index)))
- {
- memset(current_sampler, 0, sizeof(*current_sampler));
- }
- else
- {
- context.samplers = realloc(context.samplers,
- ++context.sampler_count * sizeof(*context.samplers));
- current_sampler = &context.samplers[context.sampler_count - 1];
- memset(current_sampler, 0, sizeof(*current_sampler));
- }
- current_sampler->slot = index;
- current_sampler->filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
- current_sampler->u_address = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
- current_sampler->v_address = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
- current_sampler->w_address = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
- }
- else if (sscanf(line, "[texture %u]\n", &index))
- {
- state = STATE_TEXTURE;
-
- if ((current_texture = get_texture(&context, index)))
- {
- free_texture(current_texture);
- }
- else
- {
- context.textures = realloc(context.textures,
- ++context.texture_count * sizeof(*context.textures));
- current_texture = &context.textures[context.texture_count - 1];
- memset(current_texture, 0, sizeof(*current_texture));
- }
- current_texture->slot = index;
- current_texture->format = DXGI_FORMAT_R32G32B32A32_FLOAT;
- current_texture->data_type = TEXTURE_DATA_FLOAT;
- current_texture->texel_size = 16;
- }
- else if (!strcmp(line, "[test]\n"))
- {
- state = STATE_TEST;
- }
- else if (!strcmp(line, "[preproc]\n"))
- {
- state = STATE_PREPROC;
- }
- else if (!strcmp(line, "[preproc fail]\n"))
- {
- state = STATE_PREPROC_INVALID;
- }
-
- vkd3d_test_set_context("Section %.*s, line %u", strlen(line) - 1, line, line_number);
- }
- else if (line[0] != '%' && line[0] != '\n')
- {
- switch (state)
- {
- case STATE_NONE:
- fatal_error("Malformed line '%s'.\n", line);
- break;
-
- case STATE_PREPROC:
- case STATE_PREPROC_INVALID:
- case STATE_SHADER_INVALID_PIXEL:
- case STATE_SHADER_PIXEL:
- {
- size_t len = strlen(line);
-
- vkd3d_array_reserve((void **)&shader_source, &shader_source_size, shader_source_len + len + 1, 1);
- memcpy(shader_source + shader_source_len, line, len + 1);
- shader_source_len += len;
- break;
- }
-
- case STATE_SAMPLER:
- parse_sampler_directive(current_sampler, line);
- break;
-
- case STATE_TEXTURE:
- parse_texture_directive(current_texture, line);
- break;
-
- case STATE_TEST:
- parse_test_directive(&context, line);
- break;
- }
- }
- }
-
- if (context.ps_code)
- ID3D10Blob_Release(context.ps_code);
- for (i = 0; i < context.texture_count; ++i)
- free_texture(&context.textures[i]);
- destroy_test_context(&context.c);
-
- fclose(f);
+ run_shader_tests(argc, argv, &d3d12_runner_ops);
}
--
2.34.1