This allows to declare SRV buffers in the shader tests using `[buffer srv n]` blocks, and passing them to the different backends.
Also, 1/2 includes a missing bit required to parse `Buffer<>` types in the HLSL compiler.
This is a step towards supporting StructuredBuffer types in further patches.
From: Francisco Casas fcasas@codeweavers.com
--- libs/vkd3d-shader/hlsl.c | 5 ++++- libs/vkd3d-shader/hlsl.y | 6 +++++- 2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 1e2474451..e2ae8fa50 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -2190,7 +2190,10 @@ struct vkd3d_string_buffer *hlsl_type_to_string(struct hlsl_ctx *ctx, const stru
assert(type->sampler_dim < ARRAY_SIZE(dimensions)); assert(type->e.resource_format->base_type < ARRAY_SIZE(base_types)); - vkd3d_string_buffer_printf(string, "Texture%s", dimensions[type->sampler_dim]); + if (type->sampler_dim == HLSL_SAMPLER_DIM_BUFFER) + vkd3d_string_buffer_printf(string, "Buffer"); + else + vkd3d_string_buffer_printf(string, "Texture%s", dimensions[type->sampler_dim]); if ((inner_string = hlsl_type_to_string(ctx, type->e.resource_format))) { vkd3d_string_buffer_printf(string, "<%s>", inner_string->buffer); diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index b11cbde26..3258446f3 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -5827,7 +5827,11 @@ parameter: }
texture_type: - KW_TEXTURE1D + KW_BUFFER + { + $$ = HLSL_SAMPLER_DIM_BUFFER; + } + | KW_TEXTURE1D { $$ = HLSL_SAMPLER_DIM_1D; }
From: Francisco Casas fcasas@codeweavers.com
--- Makefile.am | 1 + tests/hlsl/srv-buffer.shader_test | 45 +++++++++++++++++++++++++++++++ tests/shader_runner.c | 13 +++++++++ tests/shader_runner.h | 1 + tests/shader_runner_d3d11.c | 19 +++++++++++++ tests/shader_runner_d3d12.c | 32 +++++++++++++++++++++- tests/shader_runner_d3d9.c | 5 ++++ tests/shader_runner_gl.c | 34 ++++++++++++++++++++--- tests/shader_runner_vulkan.c | 32 +++++++++++++++++++--- 9 files changed, 174 insertions(+), 8 deletions(-) create mode 100644 tests/hlsl/srv-buffer.shader_test
diff --git a/Makefile.am b/Makefile.am index bc648b631..1cff1a61c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -165,6 +165,7 @@ vkd3d_shader_tests = \ tests/hlsl/single-numeric-initializer.shader_test \ tests/hlsl/smoothstep.shader_test \ tests/hlsl/sqrt.shader_test \ + tests/hlsl/srv-buffer.shader_test \ tests/hlsl/state-block-syntax.shader_test \ tests/hlsl/static-initializer.shader_test \ tests/hlsl/step.shader_test \ diff --git a/tests/hlsl/srv-buffer.shader_test b/tests/hlsl/srv-buffer.shader_test new file mode 100644 index 000000000..adac5bee0 --- /dev/null +++ b/tests/hlsl/srv-buffer.shader_test @@ -0,0 +1,45 @@ +[require] +shader model >= 4.0 + + +[buffer srv 0] +size (1, 4) + +0.0 1.0 2.0 3.0 +4.0 5.0 6.0 7.0 +8.0 9.0 10.0 11.0 +12.0 13.0 14.0 15.0 + + +[pixel shader] +float4 a; +Buffer<float4> buffer; +float4 b; + +float4 main() : sv_target +{ + return float4(a.y, b.z, buffer[1].xw); +} + +[test] +uniform 0 float4 100 200 300 400 +uniform 4 float4 1000 2000 3000 4000 +todo(sm>=6) draw quad +probe all rgba (200, 3000, 4, 7) + + +[pixel shader] +float4 a; +Buffer<float3> buffer; +float4 b; + +float4 main() : sv_target +{ + return float4(b.w, buffer[2]); +} + +[test] +uniform 0 float4 100 200 300 400 +uniform 4 float4 1000 2000 3000 4000 +todo(sm>=6) draw quad +probe all rgba (4000.0, 8.0, 9.0, 10.0) diff --git a/tests/shader_runner.c b/tests/shader_runner.c index bac3a8f26..86aac01ab 100644 --- a/tests/shader_runner.c +++ b/tests/shader_runner.c @@ -1406,6 +1406,19 @@ void run_shader_tests(struct shader_runner *runner, const struct shader_runner_o current_resource.texel_size = 16; current_resource.level_count = 1; } + else if (sscanf(line, "[buffer srv %u]\n", &index)) + { + state = STATE_RESOURCE; + + memset(¤t_resource, 0, sizeof(current_resource)); + + current_resource.slot = index; + current_resource.type = RESOURCE_TYPE_BUFFER_SRV; + current_resource.format = DXGI_FORMAT_R32G32B32A32_FLOAT; + current_resource.data_type = TEXTURE_DATA_FLOAT; + current_resource.texel_size = 16; + current_resource.level_count = 1; + } else if (sscanf(line, "[vertex buffer %u]\n", &index)) { state = STATE_RESOURCE; diff --git a/tests/shader_runner.h b/tests/shader_runner.h index 163439477..9097967e7 100644 --- a/tests/shader_runner.h +++ b/tests/shader_runner.h @@ -70,6 +70,7 @@ enum resource_type RESOURCE_TYPE_TEXTURE, RESOURCE_TYPE_UAV, RESOURCE_TYPE_BUFFER_UAV, + RESOURCE_TYPE_BUFFER_SRV, RESOURCE_TYPE_VERTEX_BUFFER, };
diff --git a/tests/shader_runner_d3d11.c b/tests/shader_runner_d3d11.c index 1a62b20cd..f9ff18eac 100644 --- a/tests/shader_runner_d3d11.c +++ b/tests/shader_runner_d3d11.c @@ -424,6 +424,22 @@ static struct resource *d3d11_runner_create_resource(struct shader_runner *r, co break; }
+ case RESOURCE_TYPE_BUFFER_SRV: + { + D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc; + + resource->buffer = create_buffer(device, D3D11_BIND_SHADER_RESOURCE, params->data_size, params->data); + resource->resource = (ID3D11Resource *)resource->buffer; + + srv_desc.Format = params->format; + srv_desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; + srv_desc.Buffer.FirstElement = 0; + srv_desc.Buffer.NumElements = params->data_size / params->texel_size; + hr = ID3D11Device_CreateShaderResourceView(device, resource->resource, &srv_desc, &resource->srv); + ok(hr == S_OK, "Failed to create view, hr %#lx.\n", hr); + break; + } + case RESOURCE_TYPE_BUFFER_UAV: { D3D11_UNORDERED_ACCESS_VIEW_DESC uav_desc; @@ -518,6 +534,7 @@ static bool d3d11_runner_dispatch(struct shader_runner *r, unsigned int x, unsig switch (resource->r.type) { case RESOURCE_TYPE_TEXTURE: + case RESOURCE_TYPE_BUFFER_SRV: ID3D11DeviceContext_CSSetShaderResources(context, resource->r.slot, 1, &resource->srv); break;
@@ -605,6 +622,7 @@ static bool d3d11_runner_draw(struct shader_runner *r, break;
case RESOURCE_TYPE_TEXTURE: + case RESOURCE_TYPE_BUFFER_SRV: ID3D11DeviceContext_PSSetShaderResources(context, resource->r.slot, 1, &resource->srv); break;
@@ -716,6 +734,7 @@ static struct resource_readback *d3d11_runner_get_resource_readback(struct shade
case RESOURCE_TYPE_VERTEX_BUFFER: case RESOURCE_TYPE_TEXTURE: + case RESOURCE_TYPE_BUFFER_SRV: assert(0); }
diff --git a/tests/shader_runner_d3d12.c b/tests/shader_runner_d3d12.c index d6b80d9ea..17d5a7d14 100644 --- a/tests/shader_runner_d3d12.c +++ b/tests/shader_runner_d3d12.c @@ -119,7 +119,7 @@ static struct resource *d3d12_runner_create_resource(struct shader_runner *r, co struct d3d12_shader_runner *runner = d3d12_shader_runner(r); struct test_context *test_context = &runner->test_context; ID3D12Device *device = test_context->device; - D3D12_SUBRESOURCE_DATA resource_data[2]; + D3D12_SUBRESOURCE_DATA resource_data[2] = {0}; struct d3d12_resource *resource; unsigned int buffer_offset = 0;
@@ -187,6 +187,33 @@ static struct resource *d3d12_runner_create_resource(struct shader_runner *r, co NULL, NULL, get_cpu_descriptor_handle(test_context, runner->heap, resource->r.slot + MAX_RESOURCES)); break;
+ case RESOURCE_TYPE_BUFFER_SRV: + { + D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = { 0 }; + + if (!runner->heap) + runner->heap = create_gpu_descriptor_heap(device, + D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, MAX_RESOURCE_DESCRIPTORS); + + resource->resource = create_default_buffer(device, params->data_size, + 0, D3D12_RESOURCE_STATE_COPY_DEST); + upload_buffer_data_with_states(resource->resource, 0, params->data_size, resource_data[0].pData, + test_context->queue, test_context->list, + RESOURCE_STATE_DO_NOT_CHANGE, + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); + reset_command_list(test_context->list, test_context->allocator); + + srv_desc.Format = params->format; + srv_desc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; + srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + srv_desc.Buffer.NumElements = params->width * params->height; + + ID3D12Device_CreateShaderResourceView(device, resource->resource, + &srv_desc, get_cpu_descriptor_handle(test_context, runner->heap, resource->r.slot)); + + break; + } + case RESOURCE_TYPE_BUFFER_UAV: { D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = { 0 }; @@ -263,6 +290,7 @@ static ID3D12RootSignature *d3d12_runner_create_root_signature(struct d3d12_shad { case RESOURCE_TYPE_TEXTURE: case RESOURCE_TYPE_UAV: + case RESOURCE_TYPE_BUFFER_SRV: case RESOURCE_TYPE_BUFFER_UAV: range = &resource->descriptor_range;
@@ -368,6 +396,7 @@ static bool d3d12_runner_dispatch(struct shader_runner *r, unsigned int x, unsig switch (resource->r.type) { case RESOURCE_TYPE_TEXTURE: + case RESOURCE_TYPE_BUFFER_SRV: ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(command_list, resource->root_index, get_gpu_descriptor_handle(test_context, runner->heap, resource->r.slot)); break; @@ -509,6 +538,7 @@ static bool d3d12_runner_draw(struct shader_runner *r, break;
case RESOURCE_TYPE_TEXTURE: + case RESOURCE_TYPE_BUFFER_SRV: ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(command_list, resource->root_index, get_gpu_descriptor_handle(test_context, runner->heap, resource->r.slot)); break; diff --git a/tests/shader_runner_d3d9.c b/tests/shader_runner_d3d9.c index 0b33c1c53..b8a398348 100644 --- a/tests/shader_runner_d3d9.c +++ b/tests/shader_runner_d3d9.c @@ -257,6 +257,10 @@ static struct resource *d3d9_runner_create_resource(struct shader_runner *r, con break; }
+ case RESOURCE_TYPE_BUFFER_SRV: + fatal_error("Buffer resources are not supported.\n"); + break; + case RESOURCE_TYPE_UAV: case RESOURCE_TYPE_BUFFER_UAV: fatal_error("UAVs are not supported.\n"); @@ -384,6 +388,7 @@ static bool d3d9_runner_draw(struct shader_runner *r, break;
case RESOURCE_TYPE_UAV: + case RESOURCE_TYPE_BUFFER_SRV: case RESOURCE_TYPE_BUFFER_UAV: vkd3d_unreachable();
diff --git a/tests/shader_runner_gl.c b/tests/shader_runner_gl.c index 9a3dd7104..d8b9ee437 100644 --- a/tests/shader_runner_gl.c +++ b/tests/shader_runner_gl.c @@ -332,6 +332,7 @@ static struct resource *gl_runner_create_resource(struct shader_runner *r, const } break;
+ case RESOURCE_TYPE_BUFFER_SRV: case RESOURCE_TYPE_BUFFER_UAV: resource->format = get_format_info(params->format);
@@ -366,6 +367,7 @@ static void gl_runner_destroy_resource(struct shader_runner *r, struct resource glDeleteTextures(1, &resource->id); break;
+ case RESOURCE_TYPE_BUFFER_SRV: case RESOURCE_TYPE_BUFFER_UAV: glDeleteTextures(1, &resource->tbo_id); /* Fall-through. */ @@ -455,7 +457,10 @@ static bool compile_shader(struct gl_runner *runner, ID3DBlob *blob, struct vkd3 sampler->sampler_space = s->sampler_space; sampler->sampler_index = s->sampler_index; sampler->shader_visibility = VKD3D_SHADER_VISIBILITY_ALL; - sampler->flags = VKD3D_SHADER_BINDING_FLAG_IMAGE; + /* We don't know if this combined sampler was created from a SRV buffer or a SRV image, so + * we pass both flags, otherwise the combined sampler won't be recognized when emitting the + * SPIR-V, which will result in a missing assertion. */ + sampler->flags = VKD3D_SHADER_BINDING_FLAG_IMAGE | VKD3D_SHADER_BINDING_FLAG_BUFFER; sampler->binding.set = 0; sampler->binding.binding = runner->combined_sampler_count++; sampler->binding.count = 1; @@ -485,6 +490,18 @@ static bool compile_shader(struct gl_runner *runner, ID3DBlob *blob, struct vkd3
switch (resource->r.type) { + case RESOURCE_TYPE_BUFFER_SRV: + binding = &bindings[interface_info.binding_count++]; + binding->type = VKD3D_SHADER_DESCRIPTOR_TYPE_SRV; + binding->register_space = 0; + binding->register_index = resource->r.slot; + binding->shader_visibility = VKD3D_SHADER_VISIBILITY_ALL; + binding->flags = VKD3D_SHADER_BINDING_FLAG_BUFFER; + binding->binding.set = 0; + binding->binding.binding = resource->r.slot; + binding->binding.count = 1; + break; + case RESOURCE_TYPE_UAV: case RESOURCE_TYPE_BUFFER_UAV: binding = &bindings[interface_info.binding_count++]; @@ -624,6 +641,7 @@ static bool gl_runner_dispatch(struct shader_runner *r, unsigned int x, unsigned break;
case RESOURCE_TYPE_TEXTURE: + case RESOURCE_TYPE_BUFFER_SRV: case RESOURCE_TYPE_BUFFER_UAV: trace("RESOURCE TYPE %#x.\n", resource->r.type); break; @@ -819,15 +837,20 @@ static bool gl_runner_draw(struct shader_runner *r, const struct vkd3d_shader_combined_resource_sampler *s = &runner->combined_samplers[i]; struct resource *resource; struct sampler *sampler; + bool is_buffer;
if (s->resource_space || s->sampler_space) fatal_error("Unsupported register space.\n");
- if (!(resource = shader_runner_get_resource(r, RESOURCE_TYPE_TEXTURE, s->resource_index))) + if ((resource = shader_runner_get_resource(r, RESOURCE_TYPE_TEXTURE, s->resource_index))) + is_buffer = false; + else if ((resource = shader_runner_get_resource(r, RESOURCE_TYPE_BUFFER_SRV, s->resource_index))) + is_buffer = true; + else fatal_error("Resource not found.\n");
glActiveTexture(GL_TEXTURE0 + s->binding.binding); - glBindTexture(GL_TEXTURE_2D, gl_resource(resource)->id); + glBindTexture(is_buffer ? GL_TEXTURE_BUFFER : GL_TEXTURE_2D, gl_resource(resource)->id); if (s->sampler_index == VKD3D_SHADER_DUMMY_SAMPLER_INDEX) continue;
@@ -856,6 +879,11 @@ static bool gl_runner_draw(struct shader_runner *r, case RESOURCE_TYPE_TEXTURE: break;
+ case RESOURCE_TYPE_BUFFER_SRV: + glBindImageTexture(resource->r.slot, resource->id, 0, GL_TRUE, + 0, GL_READ_ONLY, resource->format->internal_format); + break; + case RESOURCE_TYPE_UAV: glBindImageTexture(resource->r.slot, resource->id, 0, GL_TRUE, 0, GL_READ_WRITE, resource->format->internal_format); diff --git a/tests/shader_runner_vulkan.c b/tests/shader_runner_vulkan.c index bb6b3a30a..bdfeb5044 100644 --- a/tests/shader_runner_vulkan.c +++ b/tests/shader_runner_vulkan.c @@ -349,10 +349,19 @@ static struct resource *vulkan_runner_create_resource(struct shader_runner *r, c break; }
+ case RESOURCE_TYPE_BUFFER_SRV: case RESOURCE_TYPE_BUFFER_UAV: + { + VkBufferUsageFlagBits usage; + + if (params->type == RESOURCE_TYPE_BUFFER_UAV) + usage = VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; + else + usage = VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT; + format = vkd3d_get_vk_format(params->format);
- resource->buffer = create_buffer(runner, params->data_size, VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT, + resource->buffer = create_buffer(runner, params->data_size, usage, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &resource->memory); resource->buffer_view = create_buffer_view(runner, resource->buffer, format);
@@ -360,6 +369,7 @@ static struct resource *vulkan_runner_create_resource(struct shader_runner *r, c memcpy(data, params->data, params->data_size); VK_CALL(vkUnmapMemory(device, resource->memory)); break; + }
case RESOURCE_TYPE_VERTEX_BUFFER: resource->buffer = create_buffer(runner, params->data_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, @@ -492,6 +502,7 @@ static bool compile_shader(struct vulkan_shader_runner *runner, const char *sour
case RESOURCE_TYPE_TEXTURE: case RESOURCE_TYPE_UAV: + case RESOURCE_TYPE_BUFFER_SRV: case RESOURCE_TYPE_BUFFER_UAV: binding = &bindings[interface_info.binding_count++]; if (resource->r.type == RESOURCE_TYPE_UAV || resource->r.type == RESOURCE_TYPE_BUFFER_UAV) @@ -501,7 +512,7 @@ static bool compile_shader(struct vulkan_shader_runner *runner, const char *sour binding->register_space = 0; binding->register_index = resource->r.slot; binding->shader_visibility = VKD3D_SHADER_VISIBILITY_ALL; - if (resource->r.type == RESOURCE_TYPE_BUFFER_UAV) + if (resource->r.type == RESOURCE_TYPE_BUFFER_SRV || resource->r.type == RESOURCE_TYPE_BUFFER_UAV) binding->flags = VKD3D_SHADER_BINDING_FLAG_BUFFER; else binding->flags = VKD3D_SHADER_BINDING_FLAG_IMAGE; @@ -684,6 +695,7 @@ static VkPipeline create_graphics_pipeline(struct vulkan_shader_runner *runner, { case RESOURCE_TYPE_TEXTURE: case RESOURCE_TYPE_UAV: + case RESOURCE_TYPE_BUFFER_SRV: case RESOURCE_TYPE_BUFFER_UAV: break;
@@ -815,6 +827,7 @@ static VkDescriptorSetLayout create_descriptor_set_layout(struct vulkan_shader_r
case RESOURCE_TYPE_TEXTURE: case RESOURCE_TYPE_UAV: + case RESOURCE_TYPE_BUFFER_SRV: case RESOURCE_TYPE_BUFFER_UAV: binding = &bindings[set_desc.bindingCount++];
@@ -823,6 +836,8 @@ static VkDescriptorSetLayout create_descriptor_set_layout(struct vulkan_shader_r binding->binding = resource->binding; if (resource->r.type == RESOURCE_TYPE_UAV) binding->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + else if (resource->r.type == RESOURCE_TYPE_BUFFER_SRV) + binding->descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; else if (resource->r.type == RESOURCE_TYPE_BUFFER_UAV) binding->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; else @@ -909,12 +924,19 @@ static void bind_resources(struct vulkan_shader_runner *runner, VkPipelineBindPo VK_CALL(vkUpdateDescriptorSets(runner->device, 1, &write, 0, NULL)); break;
+ case RESOURCE_TYPE_BUFFER_SRV: case RESOURCE_TYPE_BUFFER_UAV: write.dstSet = descriptor_set; write.dstBinding = resource->binding; write.dstArrayElement = 0; write.descriptorCount = 1; - write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; + write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; + + if (resource->r.type == RESOURCE_TYPE_BUFFER_UAV) + { + write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; + } + write.pTexelBufferView = &resource->buffer_view;
VK_CALL(vkUpdateDescriptorSets(runner->device, 1, &write, 0, NULL)); @@ -1261,7 +1283,7 @@ static bool init_vulkan_runner(struct vulkan_shader_runner *runner) VkInstanceCreateInfo instance_desc = {.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO}; VkDeviceCreateInfo device_desc = {.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO}; VkPhysicalDeviceFeatures ret_features, features; - VkDescriptorPoolSize descriptor_pool_sizes[4]; + VkDescriptorPoolSize descriptor_pool_sizes[5]; static const float queue_priority = 1.0f; VkFormatProperties format_props; uint32_t count, graphics_index; @@ -1388,6 +1410,8 @@ static bool init_vulkan_runner(struct vulkan_shader_runner *runner) descriptor_pool_sizes[2].descriptorCount = MAX_RESOURCES; descriptor_pool_sizes[3].type = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; descriptor_pool_sizes[3].descriptorCount = MAX_RESOURCES; + descriptor_pool_sizes[4].type = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; + descriptor_pool_sizes[4].descriptorCount = MAX_RESOURCES;
descriptor_pool_desc.maxSets = 1; descriptor_pool_desc.poolSizeCount = ARRAY_SIZE(descriptor_pool_sizes);
Do we need the glBindImageTexture() (and corresponding binding in compiler_shader()) in the OpenGL runner? I would have expected the combined sampler binding to be sufficient on its own.
@@ -624,6 +641,7 @@ static bool gl_runner_dispatch(struct shader_runner *r, unsigned int x, unsigned break; case RESOURCE_TYPE_TEXTURE: + case RESOURCE_TYPE_BUFFER_SRV: case RESOURCE_TYPE_BUFFER_UAV: trace("RESOURCE TYPE %#x.\n", resource->r.type); break;
Oops, looks like I left in a debug trace()...
Do we need the glBindImageTexture() (and corresponding binding in compiler_shader()) in the OpenGL runner? I would have expected the combined sampler binding to be sufficient on its own.
Oh, right, that is not necessary.
Oops, looks like I left in a debug trace()...
I removed the trace() message while at it then.
I also realizer that I was incorrectly passing `gl_resource(resource)->id` instead of `gl_resource(resource)->tbo_id` to glBindTexture() for buffers, and I added an extra test.