mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-26 05:58:11 +02:00
1578 lines
58 KiB
C
1578 lines
58 KiB
C
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#define VK_PROTOTYPES
|
|
#include <vulkan/vulkan.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <stdarg.h>
|
|
#include <poll.h>
|
|
#include <libpng16/png.h>
|
|
|
|
#include "vk-spirv.h"
|
|
|
|
#define for_each_bit(b, dword) \
|
|
for (uint32_t __dword = (dword); \
|
|
(b) = __builtin_ffs(__dword) - 1, __dword; \
|
|
__dword &= ~(1 << (b)))
|
|
|
|
static inline uint32_t
|
|
align_u32(uint32_t value, uint32_t alignment)
|
|
{
|
|
return (value + alignment - 1) & ~(alignment - 1);
|
|
}
|
|
|
|
static void
|
|
fail_if(int cond, const char *format, ...)
|
|
{
|
|
va_list args;
|
|
|
|
if (!cond)
|
|
return;
|
|
|
|
va_start(args, format);
|
|
vfprintf(stderr, format, args);
|
|
va_end(args);
|
|
|
|
exit(1);
|
|
}
|
|
|
|
static void
|
|
write_png(char *path, int32_t width, int32_t height, int32_t stride, void *pixels)
|
|
{
|
|
FILE *f = NULL;
|
|
png_structp png_writer = NULL;
|
|
png_infop png_info = NULL;
|
|
|
|
uint8_t *rows[height];
|
|
|
|
for (int32_t y = 0; y < height; y++)
|
|
rows[y] = pixels + y * stride;
|
|
|
|
f = fopen(path, "wb");
|
|
fail_if(!f, "failed to open file for writing: %s", path);
|
|
|
|
png_writer = png_create_write_struct(PNG_LIBPNG_VER_STRING,
|
|
NULL, NULL, NULL);
|
|
fail_if (!png_writer, "failed to create png writer");
|
|
|
|
png_info = png_create_info_struct(png_writer);
|
|
fail_if(!png_info, "failed to create png writer info");
|
|
|
|
png_init_io(png_writer, f);
|
|
png_set_IHDR(png_writer, png_info,
|
|
width, height,
|
|
8, PNG_COLOR_TYPE_RGBA,
|
|
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
|
|
PNG_FILTER_TYPE_DEFAULT);
|
|
png_write_info(png_writer, png_info);
|
|
png_set_rows(png_writer, png_info, rows);
|
|
png_write_png(png_writer, png_info, PNG_TRANSFORM_IDENTITY, NULL);
|
|
|
|
png_destroy_write_struct(&png_writer, &png_info);
|
|
|
|
fclose(f);
|
|
}
|
|
|
|
static void *
|
|
test_alloc(void* pUserData,
|
|
size_t size,
|
|
size_t alignment,
|
|
VkSystemAllocType allocType)
|
|
{
|
|
return malloc(size);
|
|
}
|
|
|
|
static void
|
|
test_free(void* pUserData,
|
|
void* pMem)
|
|
{
|
|
free(pMem);
|
|
}
|
|
|
|
#define GLSL(src) "#version 330\n" #src
|
|
|
|
static void
|
|
create_pipeline(VkDevice device, VkPipeline *pipeline,
|
|
VkPipelineLayout pipeline_layout)
|
|
{
|
|
VkPipelineIaStateCreateInfo ia_create_info = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_IA_STATE_CREATE_INFO,
|
|
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
|
|
.disableVertexReuse = false,
|
|
.primitiveRestartEnable = false,
|
|
.primitiveRestartIndex = 0
|
|
};
|
|
|
|
VkShader vs = GLSL_VK_SHADER(device, VERTEX,
|
|
layout(location = 0) in vec4 a_position;
|
|
layout(location = 1) in vec4 a_color;
|
|
layout(set = 0, binding = 0) uniform block1 {
|
|
vec4 color;
|
|
} u1;
|
|
layout(set = 0, binding = 1) uniform block2 {
|
|
vec4 color;
|
|
} u2;
|
|
layout(set = 1, binding = 0) uniform block3 {
|
|
vec4 color;
|
|
} u3;
|
|
out vec4 v_color;
|
|
void main()
|
|
{
|
|
gl_Position = a_position;
|
|
v_color = a_color + u1.color + u2.color + u3.color;
|
|
}
|
|
);
|
|
|
|
VkShader fs = GLSL_VK_SHADER(device, FRAGMENT,
|
|
out vec4 f_color;
|
|
in vec4 v_color;
|
|
layout(set = 0, binding = 0) uniform sampler2D tex;
|
|
void main()
|
|
{
|
|
f_color = v_color + texture(tex, vec2(0.1, 0.1));
|
|
}
|
|
);
|
|
|
|
VkPipelineShaderStageCreateInfo vs_create_info = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
.pNext = &ia_create_info,
|
|
.shader = {
|
|
.stage = VK_SHADER_STAGE_VERTEX,
|
|
.shader = vs,
|
|
.linkConstBufferCount = 0,
|
|
.pLinkConstBufferInfo = NULL,
|
|
.pSpecializationInfo = NULL
|
|
}
|
|
};
|
|
|
|
VkPipelineShaderStageCreateInfo fs_create_info = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
.pNext = &vs_create_info,
|
|
.shader = {
|
|
.stage = VK_SHADER_STAGE_FRAGMENT,
|
|
.shader = fs,
|
|
.linkConstBufferCount = 0,
|
|
.pLinkConstBufferInfo = NULL,
|
|
.pSpecializationInfo = NULL
|
|
}
|
|
};
|
|
|
|
VkPipelineVertexInputCreateInfo vi_create_info = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_CREATE_INFO,
|
|
.pNext = &fs_create_info,
|
|
.bindingCount = 2,
|
|
.pVertexBindingDescriptions = (VkVertexInputBindingDescription[]) {
|
|
{
|
|
.binding = 0,
|
|
.strideInBytes = 16,
|
|
.stepRate = VK_VERTEX_INPUT_STEP_RATE_VERTEX
|
|
},
|
|
{
|
|
.binding = 1,
|
|
.strideInBytes = 0,
|
|
.stepRate = VK_VERTEX_INPUT_STEP_RATE_VERTEX
|
|
}
|
|
},
|
|
.attributeCount = 2,
|
|
.pVertexAttributeDescriptions = (VkVertexInputAttributeDescription[]) {
|
|
{
|
|
.location = 0,
|
|
.binding = 0,
|
|
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
|
|
.offsetInBytes = 0
|
|
},
|
|
{
|
|
.location = 1,
|
|
.binding = 1,
|
|
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
|
|
.offsetInBytes = 0
|
|
}
|
|
}
|
|
};
|
|
|
|
VkPipelineRsStateCreateInfo rs_create_info = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_RS_STATE_CREATE_INFO,
|
|
.pNext = &vi_create_info,
|
|
|
|
.depthClipEnable = true,
|
|
.rasterizerDiscardEnable = false,
|
|
.fillMode = VK_FILL_MODE_SOLID,
|
|
.cullMode = VK_CULL_MODE_NONE,
|
|
.frontFace = VK_FRONT_FACE_CCW
|
|
};
|
|
|
|
VkPipelineCbStateCreateInfo cb_create_info = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_CB_STATE_CREATE_INFO,
|
|
.pNext = &rs_create_info,
|
|
.attachmentCount = 1,
|
|
.pAttachments = (VkPipelineCbAttachmentState []) {
|
|
{ .channelWriteMask = VK_CHANNEL_A_BIT |
|
|
VK_CHANNEL_R_BIT | VK_CHANNEL_G_BIT | VK_CHANNEL_B_BIT },
|
|
}
|
|
};
|
|
|
|
vkCreateGraphicsPipeline(device,
|
|
&(VkGraphicsPipelineCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
|
.pNext = &cb_create_info,
|
|
.flags = 0,
|
|
.layout = pipeline_layout
|
|
},
|
|
pipeline);
|
|
|
|
|
|
vkDestroyObject(device, VK_OBJECT_TYPE_SHADER, fs);
|
|
vkDestroyObject(device, VK_OBJECT_TYPE_SHADER, vs);
|
|
}
|
|
|
|
static void
|
|
test_timestamp(VkDevice device, VkQueue queue)
|
|
{
|
|
VkBuffer buffer;
|
|
vkCreateBuffer(device,
|
|
&(VkBufferCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
|
.size = 1024,
|
|
.usage = VK_BUFFER_USAGE_GENERAL,
|
|
.flags = 0
|
|
},
|
|
&buffer);
|
|
|
|
VkMemoryRequirements buffer_requirements;
|
|
size_t size = sizeof(buffer_requirements);
|
|
vkGetObjectInfo(device, VK_OBJECT_TYPE_BUFFER, buffer,
|
|
VK_OBJECT_INFO_TYPE_MEMORY_REQUIREMENTS,
|
|
&size, &buffer_requirements);
|
|
|
|
VkDeviceMemory mem;
|
|
vkAllocMemory(device,
|
|
&(VkMemoryAllocInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO,
|
|
.allocationSize = buffer_requirements.size,
|
|
.memProps = VK_MEMORY_PROPERTY_HOST_DEVICE_COHERENT_BIT,
|
|
.memPriority = VK_MEMORY_PRIORITY_NORMAL
|
|
},
|
|
&mem);
|
|
|
|
void *map;
|
|
vkMapMemory(device, mem, 0, buffer_requirements.size, 0, &map);
|
|
memset(map, 0x11, buffer_requirements.size);
|
|
|
|
vkQueueBindObjectMemory(queue, VK_OBJECT_TYPE_BUFFER,
|
|
buffer,
|
|
0, /* allocation index; for objects which need to bind to multiple mems */
|
|
mem, 0);
|
|
|
|
VkCmdBuffer cmdBuffer;
|
|
vkCreateCommandBuffer(device,
|
|
&(VkCmdBufferCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO,
|
|
.queueNodeIndex = 0,
|
|
.flags = 0
|
|
},
|
|
&cmdBuffer);
|
|
|
|
vkBeginCommandBuffer(cmdBuffer,
|
|
&(VkCmdBufferBeginInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO,
|
|
.flags = 0
|
|
});
|
|
|
|
vkCmdWriteTimestamp(cmdBuffer, VK_TIMESTAMP_TYPE_TOP, buffer, 0);
|
|
vkCmdWriteTimestamp(cmdBuffer, VK_TIMESTAMP_TYPE_BOTTOM, buffer, 8);
|
|
|
|
vkEndCommandBuffer(cmdBuffer);
|
|
|
|
vkQueueSubmit(queue, 1, &cmdBuffer, 0);
|
|
|
|
vkQueueWaitIdle(queue);
|
|
|
|
vkDestroyObject(device, VK_OBJECT_TYPE_BUFFER, buffer);
|
|
vkDestroyObject(device, VK_OBJECT_TYPE_COMMAND_BUFFER, cmdBuffer);
|
|
|
|
uint64_t *results = map;
|
|
printf("top timestamp: %20ld (%016lx)\n", results[0], results[0]);
|
|
printf("bottom timestamp: %20ld (%016lx)\n", results[1], results[1]);
|
|
|
|
vkUnmapMemory(device, mem);
|
|
vkFreeMemory(device, mem);
|
|
}
|
|
|
|
static void
|
|
test_buffer_copy(VkDevice device, VkQueue queue)
|
|
{
|
|
/* We'll test copying 1000k buffers */
|
|
const int buffer_size = 1024000;
|
|
|
|
VkBufferCreateInfo buffer_info = {
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
|
.size = buffer_size,
|
|
.usage = VK_BUFFER_USAGE_GENERAL,
|
|
.flags = 0
|
|
};
|
|
|
|
VkBuffer buffer1, buffer2;
|
|
vkCreateBuffer(device, &buffer_info, &buffer1);
|
|
vkCreateBuffer(device, &buffer_info, &buffer2);
|
|
|
|
VkMemoryRequirements buffer_requirements;
|
|
size_t size = sizeof(buffer_requirements);
|
|
vkGetObjectInfo(device, VK_OBJECT_TYPE_BUFFER, buffer1,
|
|
VK_OBJECT_INFO_TYPE_MEMORY_REQUIREMENTS,
|
|
&size, &buffer_requirements);
|
|
|
|
const int memory_size = buffer_requirements.size * 2;
|
|
|
|
VkDeviceMemory mem;
|
|
vkAllocMemory(device,
|
|
&(VkMemoryAllocInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO,
|
|
.allocationSize = memory_size,
|
|
.memProps = VK_MEMORY_PROPERTY_HOST_DEVICE_COHERENT_BIT,
|
|
.memPriority = VK_MEMORY_PRIORITY_NORMAL
|
|
}, &mem);
|
|
|
|
void *map;
|
|
vkMapMemory(device, mem, 0, buffer_requirements.size * 2, 0, &map);
|
|
|
|
/* Fill the first buffer_size of the memory with a pattern */
|
|
uint32_t *map32 = map;
|
|
for (unsigned i = 0; i < buffer_size / sizeof(*map32); i++)
|
|
map32[i] = i;
|
|
|
|
/* Fill the rest with 0 */
|
|
memset((char *)map + buffer_size, 0, memory_size - buffer_size);
|
|
|
|
vkQueueBindObjectMemory(queue, VK_OBJECT_TYPE_BUFFER,
|
|
buffer1,
|
|
0, /* allocation index; for objects which need to bind to multiple mems */
|
|
mem, 0);
|
|
|
|
vkQueueBindObjectMemory(queue, VK_OBJECT_TYPE_BUFFER,
|
|
buffer2,
|
|
0, /* allocation index; for objects which need to bind to multiple mems */
|
|
mem, buffer_requirements.size);
|
|
|
|
VkCmdBuffer cmdBuffer;
|
|
vkCreateCommandBuffer(device,
|
|
&(VkCmdBufferCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO,
|
|
.queueNodeIndex = 0,
|
|
.flags = 0
|
|
}, &cmdBuffer);
|
|
|
|
vkBeginCommandBuffer(cmdBuffer,
|
|
&(VkCmdBufferBeginInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO,
|
|
.flags = 0
|
|
});
|
|
|
|
vkCmdCopyBuffer(cmdBuffer, buffer1, buffer2, 1,
|
|
&(VkBufferCopy) {
|
|
.srcOffset = 0,
|
|
.destOffset = 0,
|
|
.copySize = buffer_size,
|
|
});
|
|
|
|
vkEndCommandBuffer(cmdBuffer);
|
|
|
|
vkQueueSubmit(queue, 1, &cmdBuffer, 0);
|
|
|
|
vkQueueWaitIdle(queue);
|
|
|
|
vkDestroyObject(device, VK_OBJECT_TYPE_BUFFER, buffer1);
|
|
vkDestroyObject(device, VK_OBJECT_TYPE_BUFFER, buffer2);
|
|
vkDestroyObject(device, VK_OBJECT_TYPE_COMMAND_BUFFER, cmdBuffer);
|
|
|
|
uint32_t *map32_2 = map + buffer_requirements.size;
|
|
for (unsigned i = 0; i < buffer_size / sizeof(*map32); i++) {
|
|
if (map32[i] != map32_2[i]) {
|
|
printf("buffer mismatch at dword %d: found 0x%x, expected 0x%x\n",
|
|
i, map32_2[i], map32[i]);
|
|
}
|
|
}
|
|
|
|
vkUnmapMemory(device, mem);
|
|
vkFreeMemory(device, mem);
|
|
}
|
|
|
|
static void
|
|
test_formats(VkDevice device, VkQueue queue)
|
|
{
|
|
VkFormatProperties properties;
|
|
size_t size = sizeof(properties);
|
|
uint32_t f;
|
|
|
|
static const char *features[] = {
|
|
"sampled_image",
|
|
"storage_image",
|
|
"storage_image_atomic",
|
|
"uniform_texel_buffer",
|
|
"storage_texel_buffer",
|
|
"storage_texel_buffer_atomic",
|
|
"vertex_buffer",
|
|
"color_attachment",
|
|
"color_attachment_blend",
|
|
"depth_stencil_attachment",
|
|
"conversion"
|
|
};
|
|
|
|
VkFormat format = VK_FORMAT_R32G32B32A32_SFLOAT;
|
|
vkGetFormatInfo(device, format,
|
|
VK_FORMAT_INFO_TYPE_PROPERTIES,
|
|
&size, &properties);
|
|
|
|
printf("format 0x%x:\n", format);
|
|
|
|
printf(" linear tiling features (0x%x):", properties.linearTilingFeatures);
|
|
for_each_bit(f, properties.linearTilingFeatures)
|
|
printf(" %s", features[f]);
|
|
|
|
printf("\n optimal tiling features (0x%x):", properties.optimalTilingFeatures);
|
|
for_each_bit(f, properties.optimalTilingFeatures)
|
|
printf(" %s", features[f]);
|
|
printf("\n");
|
|
}
|
|
|
|
#define TEST_DEPTH_FLAG 0x01
|
|
|
|
struct test_context {
|
|
uint32_t width, height;
|
|
VkDevice device;
|
|
VkQueue queue;
|
|
VkCmdBuffer cmdBuffer;
|
|
VkPipeline pipeline;
|
|
VkImage rt;
|
|
VkImage ds;
|
|
VkBuffer vertex_buffer;
|
|
VkBuffer image_buffer;
|
|
VkDeviceMemory mem;
|
|
void *map;
|
|
void *rt_map;
|
|
void *vertex_map;
|
|
void *image_map;
|
|
VkDynamicVpState vp_state;
|
|
VkDynamicRsState rs_state;
|
|
VkDynamicDsState ds_state;
|
|
VkDynamicCbState cb_state;
|
|
VkColorAttachmentView rt_view;
|
|
VkDepthStencilView ds_view;
|
|
uint32_t rt_size;
|
|
VkFramebuffer framebuffer;
|
|
VkRenderPass pass;
|
|
};
|
|
|
|
static void
|
|
test_prepare(struct test_context *ctx, VkDevice device, VkQueue queue, uint32_t flags)
|
|
{
|
|
ctx->device = device;
|
|
ctx->queue = queue;
|
|
|
|
vkCreateCommandBuffer(ctx->device,
|
|
&(VkCmdBufferCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO,
|
|
.queueNodeIndex = 0,
|
|
.flags = 0
|
|
},
|
|
&ctx->cmdBuffer);
|
|
|
|
vkCreateBuffer(ctx->device,
|
|
&(VkBufferCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
|
.size = 4096,
|
|
.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
|
.flags = 0
|
|
},
|
|
&ctx->vertex_buffer);
|
|
|
|
VkMemoryRequirements vb_requirements;
|
|
size_t size = sizeof(vb_requirements);
|
|
vkGetObjectInfo(ctx->device, VK_OBJECT_TYPE_BUFFER, ctx->vertex_buffer,
|
|
VK_OBJECT_INFO_TYPE_MEMORY_REQUIREMENTS,
|
|
&size, &vb_requirements);
|
|
|
|
vkCreateImage(ctx->device,
|
|
&(VkImageCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
|
.imageType = VK_IMAGE_TYPE_2D,
|
|
.format = VK_FORMAT_R8G8B8A8_UNORM,
|
|
.extent = { .width = ctx->width, .height = ctx->height, .depth = 1 },
|
|
.mipLevels = 1,
|
|
.arraySize = 1,
|
|
.samples = 1,
|
|
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
|
.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
|
|
.flags = 0,
|
|
},
|
|
&ctx->rt);
|
|
|
|
VkMemoryRequirements rt_requirements;
|
|
size = sizeof(rt_requirements);
|
|
vkGetObjectInfo(ctx->device, VK_OBJECT_TYPE_IMAGE, ctx->rt,
|
|
VK_OBJECT_INFO_TYPE_MEMORY_REQUIREMENTS,
|
|
&size, &rt_requirements);
|
|
ctx->rt_size = rt_requirements.size;
|
|
|
|
VkDepthStencilBindInfo *ds_attachment;
|
|
VkDepthStencilBindInfo ds_bind_info;
|
|
VkMemoryRequirements ds_requirements;
|
|
|
|
if (flags & TEST_DEPTH_FLAG) {
|
|
vkCreateImage(ctx->device,
|
|
&(VkImageCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
|
.imageType = VK_IMAGE_TYPE_2D,
|
|
.format = VK_FORMAT_D24_UNORM,
|
|
.extent = { .width = ctx->width, .height = ctx->height, .depth = 1 },
|
|
.mipLevels = 1,
|
|
.arraySize = 1,
|
|
.samples = 1,
|
|
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
|
.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_BIT,
|
|
.flags = 0,
|
|
},
|
|
&ctx->ds);
|
|
|
|
size = sizeof(ds_requirements);
|
|
vkGetObjectInfo(ctx->device, VK_OBJECT_TYPE_IMAGE, ctx->ds,
|
|
VK_OBJECT_INFO_TYPE_MEMORY_REQUIREMENTS,
|
|
&size, &ds_requirements);
|
|
} else {
|
|
ds_requirements.size = 0;
|
|
}
|
|
|
|
vkCreateBuffer(ctx->device,
|
|
&(VkBufferCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
|
.size = ctx->width * ctx->height * 4,
|
|
.usage = VK_BUFFER_USAGE_TRANSFER_DESTINATION_BIT,
|
|
.flags = 0
|
|
},
|
|
&ctx->image_buffer);
|
|
|
|
VkMemoryRequirements ib_requirements;
|
|
size = sizeof(ib_requirements);
|
|
vkGetObjectInfo(ctx->device, VK_OBJECT_TYPE_BUFFER, ctx->image_buffer,
|
|
VK_OBJECT_INFO_TYPE_MEMORY_REQUIREMENTS,
|
|
&size, &ib_requirements);
|
|
|
|
size_t mem_size =
|
|
align_u32(vb_requirements.size, 4096) +
|
|
align_u32(rt_requirements.size, 4096) +
|
|
align_u32(ds_requirements.size, 4096) +
|
|
align_u32(ib_requirements.size, 4096);
|
|
|
|
printf("mem size %ld\n", mem_size);
|
|
|
|
vkAllocMemory(ctx->device,
|
|
&(VkMemoryAllocInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO,
|
|
.allocationSize = mem_size,
|
|
.memProps = VK_MEMORY_PROPERTY_HOST_DEVICE_COHERENT_BIT,
|
|
.memPriority = VK_MEMORY_PRIORITY_NORMAL
|
|
},
|
|
&ctx->mem);
|
|
|
|
vkMapMemory(ctx->device, ctx->mem, 0, mem_size, 0, &ctx->map);
|
|
memset(ctx->map, 0, mem_size);
|
|
|
|
uint32_t offset = 0;
|
|
printf("vb: %ldb at %d\n", vb_requirements.size, offset);
|
|
vkQueueBindObjectMemory(ctx->queue, VK_OBJECT_TYPE_BUFFER,
|
|
ctx->vertex_buffer, 0, ctx->mem, offset);
|
|
ctx->vertex_map = ctx->map + offset;
|
|
offset = align_u32(offset + vb_requirements.size, 4096);
|
|
|
|
printf("rt: %ldb at %d\n", rt_requirements.size, offset);
|
|
vkQueueBindObjectMemory(ctx->queue, VK_OBJECT_TYPE_IMAGE,
|
|
ctx->rt, 0, ctx->mem, offset);
|
|
ctx->rt_map = ctx->map + offset;
|
|
offset = align_u32(offset + rt_requirements.size, 4096);
|
|
|
|
if (flags & TEST_DEPTH_FLAG) {
|
|
printf("ds: %ldb at %d\n", ds_requirements.size, offset);
|
|
vkQueueBindObjectMemory(ctx->queue, VK_OBJECT_TYPE_IMAGE,
|
|
ctx->ds, 0, ctx->mem, offset);
|
|
offset = align_u32(offset + ds_requirements.size, 4096);
|
|
}
|
|
|
|
printf("ib: %ldb at %d\n", ib_requirements.size, offset);
|
|
vkQueueBindObjectMemory(ctx->queue, VK_OBJECT_TYPE_BUFFER,
|
|
ctx->image_buffer, 0, ctx->mem, offset);
|
|
ctx->image_map = ctx->map + offset;
|
|
offset = align_u32(offset + ib_requirements.size, 4096);
|
|
|
|
vkCreateDynamicViewportState(ctx->device,
|
|
&(VkDynamicVpStateCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_DYNAMIC_VP_STATE_CREATE_INFO,
|
|
.viewportAndScissorCount = 1,
|
|
.pViewports = (VkViewport[]) {
|
|
{
|
|
.originX = 0,
|
|
.originY = 0,
|
|
.width = ctx->width,
|
|
.height = ctx->height,
|
|
.minDepth = -1,
|
|
.maxDepth = 1
|
|
},
|
|
},
|
|
.pScissors = (VkRect[]) {
|
|
{ { 0, 0 }, { ctx->width, ctx->height } },
|
|
}
|
|
},
|
|
&ctx->vp_state);
|
|
|
|
vkCreateDynamicRasterState(ctx->device,
|
|
&(VkDynamicRsStateCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_DYNAMIC_RS_STATE_CREATE_INFO,
|
|
},
|
|
&ctx->rs_state);
|
|
|
|
vkCreateDynamicDepthStencilState(ctx->device,
|
|
&(VkDynamicDsStateCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_DYNAMIC_DS_STATE_CREATE_INFO,
|
|
},
|
|
&ctx->ds_state);
|
|
|
|
vkCreateDynamicColorBlendState(ctx->device,
|
|
&(VkDynamicCbStateCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_DYNAMIC_CB_STATE_CREATE_INFO
|
|
},
|
|
&ctx->cb_state);
|
|
|
|
vkCreateColorAttachmentView(ctx->device,
|
|
&(VkColorAttachmentViewCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_COLOR_ATTACHMENT_VIEW_CREATE_INFO,
|
|
.image = ctx->rt,
|
|
.format = VK_FORMAT_R8G8B8A8_UNORM,
|
|
.mipLevel = 0,
|
|
.baseArraySlice = 0,
|
|
.arraySize = 1,
|
|
.msaaResolveImage = 0,
|
|
.msaaResolveSubResource = { 0, }
|
|
},
|
|
&ctx->rt_view);
|
|
|
|
if (flags & TEST_DEPTH_FLAG) {
|
|
vkCreateDepthStencilView(ctx->device,
|
|
&(VkDepthStencilViewCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_DEPTH_STENCIL_VIEW_CREATE_INFO,
|
|
.image = ctx->ds,
|
|
.mipLevel = 0,
|
|
.baseArraySlice = 0,
|
|
.arraySize = 1,
|
|
.msaaResolveImage = 0,
|
|
.msaaResolveSubResource = { 0, }
|
|
},
|
|
&ctx->ds_view);
|
|
ds_bind_info.view = ctx->ds_view;
|
|
ds_bind_info.layout = 0;
|
|
ds_attachment = &ds_bind_info;
|
|
} else {
|
|
ds_attachment = NULL;
|
|
}
|
|
|
|
vkCreateFramebuffer(ctx->device,
|
|
&(VkFramebufferCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
|
.colorAttachmentCount = 1,
|
|
.pColorAttachments = (VkColorAttachmentBindInfo[]) {
|
|
{
|
|
.view = ctx->rt_view,
|
|
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
|
|
}
|
|
},
|
|
.pDepthStencilAttachment = ds_attachment,
|
|
.sampleCount = 1,
|
|
.width = ctx->width,
|
|
.height = ctx->height,
|
|
.layers = 1
|
|
},
|
|
&ctx->framebuffer);
|
|
|
|
vkCreateRenderPass(ctx->device,
|
|
&(VkRenderPassCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
|
|
.renderArea = { { 0, 0 }, { ctx->width, ctx->height } },
|
|
.colorAttachmentCount = 1,
|
|
.extent = { },
|
|
.sampleCount = 1,
|
|
.layers = 1,
|
|
.pColorFormats = (VkFormat[]) { VK_FORMAT_R8G8B8A8_UNORM },
|
|
.pColorLayouts = (VkImageLayout[]) { VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL },
|
|
.pColorLoadOps = (VkAttachmentLoadOp[]) { VK_ATTACHMENT_LOAD_OP_CLEAR },
|
|
.pColorStoreOps = (VkAttachmentStoreOp[]) { VK_ATTACHMENT_STORE_OP_STORE },
|
|
.pColorLoadClearValues = (VkClearColor[]) {
|
|
{ .color = { .floatColor = { 0.2, 0.2, 0.2, 1.0 } }, .useRawValue = false }
|
|
},
|
|
.depthStencilFormat = VK_FORMAT_D24_UNORM,
|
|
.depthStencilLayout = 0,
|
|
.depthLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
|
|
.depthLoadClearValue = 0.5,
|
|
.depthStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
|
},
|
|
&ctx->pass);
|
|
|
|
vkBeginCommandBuffer(ctx->cmdBuffer,
|
|
&(VkCmdBufferBeginInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO,
|
|
.flags = 0
|
|
});
|
|
|
|
vkCmdBeginRenderPass(ctx->cmdBuffer,
|
|
&(VkRenderPassBegin) {
|
|
.renderPass = ctx->pass,
|
|
.framebuffer = ctx->framebuffer
|
|
});
|
|
}
|
|
|
|
static void
|
|
test_finish(struct test_context *ctx)
|
|
{
|
|
vkCmdEndRenderPass(ctx->cmdBuffer, ctx->pass);
|
|
|
|
VkBufferImageCopy copy = {
|
|
.bufferOffset = 0,
|
|
.imageSubresource = {
|
|
.aspect = VK_IMAGE_ASPECT_COLOR,
|
|
.mipLevel = 0,
|
|
.arraySlice = 0,
|
|
},
|
|
.imageOffset = { .x = 0, .y = 0, .z = 0 },
|
|
.imageExtent = { .width = ctx->width, .height = ctx->height, .depth = 1 },
|
|
};
|
|
|
|
vkCmdCopyImageToBuffer(ctx->cmdBuffer, ctx->rt, VK_IMAGE_LAYOUT_GENERAL,
|
|
ctx->image_buffer, 1, ©);
|
|
|
|
|
|
vkEndCommandBuffer(ctx->cmdBuffer);
|
|
|
|
vkQueueSubmit(ctx->queue, 1, &ctx->cmdBuffer, 0);
|
|
|
|
vkQueueWaitIdle(ctx->queue);
|
|
|
|
write_png("vk-map.png", ctx->width, ctx->height, 1024, ctx->rt_map);
|
|
write_png("vk-copy.png", ctx->width, ctx->height, 1024, ctx->image_map);
|
|
|
|
vkDestroyObject(ctx->device, VK_OBJECT_TYPE_COMMAND_BUFFER, ctx->cmdBuffer);
|
|
vkDestroyObject(ctx->device, VK_OBJECT_TYPE_PIPELINE, ctx->pipeline);
|
|
vkDestroyObject(ctx->device, VK_OBJECT_TYPE_IMAGE, ctx->rt);
|
|
vkDestroyObject(ctx->device, VK_OBJECT_TYPE_BUFFER, ctx->vertex_buffer);
|
|
vkDestroyObject(ctx->device, VK_OBJECT_TYPE_BUFFER, ctx->image_buffer);
|
|
vkUnmapMemory(ctx->device, ctx->mem);
|
|
vkFreeMemory(ctx->device, ctx->mem);
|
|
vkDestroyObject(ctx->device, VK_OBJECT_TYPE_DYNAMIC_VP_STATE, ctx->vp_state);
|
|
vkDestroyObject(ctx->device, VK_OBJECT_TYPE_DYNAMIC_RS_STATE, ctx->rs_state);
|
|
vkDestroyObject(ctx->device, VK_OBJECT_TYPE_DYNAMIC_CB_STATE, ctx->cb_state);
|
|
vkDestroyObject(ctx->device, VK_OBJECT_TYPE_COLOR_ATTACHMENT_VIEW, ctx->rt_view);
|
|
vkDestroyObject(ctx->device, VK_OBJECT_TYPE_FRAMEBUFFER, ctx->framebuffer);
|
|
vkDestroyObject(ctx->device, VK_OBJECT_TYPE_RENDER_PASS, ctx->pass);
|
|
}
|
|
|
|
static void
|
|
test_create_solid_color_pipeline(struct test_context *ctx)
|
|
{
|
|
VkPipelineIaStateCreateInfo ia_create_info = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_IA_STATE_CREATE_INFO,
|
|
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
|
|
.disableVertexReuse = false,
|
|
.primitiveRestartEnable = false,
|
|
.primitiveRestartIndex = 0
|
|
};
|
|
|
|
VkShader vs = GLSL_VK_SHADER(ctx->device, VERTEX,
|
|
layout(location = 0) in vec4 a_position;
|
|
layout(location = 1) in vec4 a_color;
|
|
out vec4 v_color;
|
|
void main()
|
|
{
|
|
gl_Position = a_position;
|
|
v_color = a_color;
|
|
}
|
|
);
|
|
|
|
VkShader fs = GLSL_VK_SHADER(ctx->device, FRAGMENT,
|
|
out vec4 f_color;
|
|
in vec4 v_color;
|
|
void main()
|
|
{
|
|
f_color = v_color;
|
|
}
|
|
);
|
|
|
|
VkPipelineShaderStageCreateInfo vs_create_info = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
.pNext = &ia_create_info,
|
|
.shader = {
|
|
.stage = VK_SHADER_STAGE_VERTEX,
|
|
.shader = vs,
|
|
.linkConstBufferCount = 0,
|
|
.pLinkConstBufferInfo = NULL,
|
|
.pSpecializationInfo = NULL
|
|
}
|
|
};
|
|
|
|
VkPipelineShaderStageCreateInfo fs_create_info = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
.pNext = &vs_create_info,
|
|
.shader = {
|
|
.stage = VK_SHADER_STAGE_FRAGMENT,
|
|
.shader = fs,
|
|
.linkConstBufferCount = 0,
|
|
.pLinkConstBufferInfo = NULL,
|
|
.pSpecializationInfo = NULL
|
|
}
|
|
};
|
|
|
|
VkPipelineVertexInputCreateInfo vi_create_info = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_CREATE_INFO,
|
|
.pNext = &fs_create_info,
|
|
.bindingCount = 2,
|
|
.pVertexBindingDescriptions = (VkVertexInputBindingDescription[]) {
|
|
{
|
|
.binding = 0,
|
|
.strideInBytes = 16,
|
|
.stepRate = VK_VERTEX_INPUT_STEP_RATE_VERTEX
|
|
},
|
|
{
|
|
.binding = 1,
|
|
.strideInBytes = 16,
|
|
.stepRate = VK_VERTEX_INPUT_STEP_RATE_INSTANCE
|
|
}
|
|
},
|
|
.attributeCount = 2,
|
|
.pVertexAttributeDescriptions = (VkVertexInputAttributeDescription[]) {
|
|
{
|
|
.location = 0,
|
|
.binding = 0,
|
|
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
|
|
.offsetInBytes = 0
|
|
},
|
|
{
|
|
.location = 1,
|
|
.binding = 1,
|
|
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
|
|
.offsetInBytes = 0
|
|
}
|
|
}
|
|
};
|
|
|
|
VkPipelineRsStateCreateInfo rs_create_info = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_RS_STATE_CREATE_INFO,
|
|
.pNext = &vi_create_info,
|
|
|
|
.depthClipEnable = true,
|
|
.rasterizerDiscardEnable = false,
|
|
.fillMode = VK_FILL_MODE_SOLID,
|
|
.cullMode = VK_CULL_MODE_NONE,
|
|
.frontFace = VK_FRONT_FACE_CCW
|
|
};
|
|
|
|
VkPipelineDsStateCreateInfo ds_create_info = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_DS_STATE_CREATE_INFO,
|
|
.pNext = &rs_create_info,
|
|
.format = VK_FORMAT_D24_UNORM,
|
|
.depthTestEnable = true,
|
|
.depthWriteEnable = true,
|
|
.depthCompareOp = VK_COMPARE_OP_GREATER
|
|
};
|
|
|
|
VkPipelineCbStateCreateInfo cb_create_info = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_CB_STATE_CREATE_INFO,
|
|
.pNext = &ds_create_info,
|
|
.attachmentCount = 1,
|
|
.pAttachments = (VkPipelineCbAttachmentState []) {
|
|
{ .channelWriteMask = VK_CHANNEL_A_BIT |
|
|
VK_CHANNEL_R_BIT | VK_CHANNEL_G_BIT | VK_CHANNEL_B_BIT },
|
|
}
|
|
};
|
|
|
|
vkCreateGraphicsPipeline(ctx->device,
|
|
&(VkGraphicsPipelineCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
|
.pNext = &cb_create_info,
|
|
.flags = 0,
|
|
.layout = VK_NULL_HANDLE
|
|
},
|
|
&ctx->pipeline);
|
|
|
|
vkDestroyObject(ctx->device, VK_OBJECT_TYPE_SHADER, fs);
|
|
vkDestroyObject(ctx->device, VK_OBJECT_TYPE_SHADER, vs);
|
|
}
|
|
|
|
static void
|
|
test_depth_stencil(VkDevice device, VkQueue queue)
|
|
{
|
|
struct test_context ctx;
|
|
|
|
ctx.width = 256;
|
|
ctx.height = 256;
|
|
|
|
test_prepare(&ctx, device, queue, TEST_DEPTH_FLAG);
|
|
test_create_solid_color_pipeline(&ctx);
|
|
|
|
static const float vertex_data[] = {
|
|
/* Triangle coordinates */
|
|
-0.5, -0.5, 0.5, 1.0,
|
|
0.5, -0.5, 0.5, 1.0,
|
|
0.0, 0.5, 0.5, 1.0,
|
|
|
|
/* Triangle coordinates */
|
|
-0.3, -0.3, 0.0, 1.0,
|
|
0.7, -0.3, 0.0, 1.0,
|
|
0.2, 0.7, 0.8, 1.0,
|
|
|
|
/* Color */
|
|
1.0, 1.0, 0.2, 1.0,
|
|
0.2, 0.2, 1.0, 1.0,
|
|
};
|
|
memcpy(ctx.vertex_map, vertex_data, sizeof(vertex_data));
|
|
|
|
vkCmdBindVertexBuffers(ctx.cmdBuffer, 0, 2,
|
|
(VkBuffer[]) { ctx.vertex_buffer, ctx.vertex_buffer },
|
|
(VkDeviceSize[]) { 0, 6 * 4 * sizeof(float) });
|
|
|
|
vkCmdBindPipeline(ctx.cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx.pipeline);
|
|
|
|
vkCmdBindDynamicStateObject(ctx.cmdBuffer,
|
|
VK_STATE_BIND_POINT_VIEWPORT, ctx.vp_state);
|
|
vkCmdBindDynamicStateObject(ctx.cmdBuffer,
|
|
VK_STATE_BIND_POINT_RASTER, ctx.rs_state);
|
|
vkCmdBindDynamicStateObject(ctx.cmdBuffer,
|
|
VK_STATE_BIND_POINT_DEPTH_STENCIL, ctx.ds_state);
|
|
vkCmdBindDynamicStateObject(ctx.cmdBuffer,
|
|
VK_STATE_BIND_POINT_COLOR_BLEND, ctx.cb_state);
|
|
|
|
vkCmdDraw(ctx.cmdBuffer, 0, 3, 0, 1);
|
|
vkCmdDraw(ctx.cmdBuffer, 3, 3, 1, 1);
|
|
|
|
test_finish(&ctx);
|
|
}
|
|
|
|
static void
|
|
test_triangle(VkDevice device, VkQueue queue)
|
|
{
|
|
uint32_t count;
|
|
|
|
VkCmdBuffer cmdBuffer;
|
|
vkCreateCommandBuffer(device,
|
|
&(VkCmdBufferCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO,
|
|
.queueNodeIndex = 0,
|
|
.flags = 0
|
|
},
|
|
&cmdBuffer);
|
|
|
|
|
|
VkDescriptorSetLayout set_layout[2];
|
|
vkCreateDescriptorSetLayout(device,
|
|
&(VkDescriptorSetLayoutCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
|
.count = 3,
|
|
.pBinding = (VkDescriptorSetLayoutBinding[]) {
|
|
{
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
.count = 2,
|
|
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
|
.pImmutableSamplers = NULL
|
|
},
|
|
{
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
|
|
.count = 1,
|
|
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
.pImmutableSamplers = NULL
|
|
},
|
|
{
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER,
|
|
.count = 1,
|
|
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
.pImmutableSamplers = NULL
|
|
}
|
|
}
|
|
},
|
|
&set_layout[0]);
|
|
|
|
vkCreateDescriptorSetLayout(device,
|
|
&(VkDescriptorSetLayoutCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
|
.count = 1,
|
|
.pBinding = (VkDescriptorSetLayoutBinding[]) {
|
|
{
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
.count = 1,
|
|
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
|
.pImmutableSamplers = NULL
|
|
}
|
|
}
|
|
},
|
|
&set_layout[1]);
|
|
|
|
VkPipelineLayout pipeline_layout;
|
|
vkCreatePipelineLayout(device,
|
|
&(VkPipelineLayoutCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
|
.descriptorSetCount = 2,
|
|
.pSetLayouts = set_layout,
|
|
},
|
|
&pipeline_layout);
|
|
|
|
VkPipeline pipeline;
|
|
create_pipeline(device, &pipeline, pipeline_layout);
|
|
|
|
VkDescriptorSet set[2];
|
|
vkAllocDescriptorSets(device, 0 /* pool */,
|
|
VK_DESCRIPTOR_SET_USAGE_STATIC,
|
|
2, set_layout, set, &count);
|
|
|
|
VkBuffer buffer;
|
|
vkCreateBuffer(device,
|
|
&(VkBufferCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
|
.size = 1024,
|
|
.usage = VK_BUFFER_USAGE_GENERAL,
|
|
.flags = 0
|
|
},
|
|
&buffer);
|
|
|
|
VkMemoryRequirements buffer_requirements;
|
|
size_t size = sizeof(buffer_requirements);
|
|
vkGetObjectInfo(device, VK_OBJECT_TYPE_BUFFER, buffer,
|
|
VK_OBJECT_INFO_TYPE_MEMORY_REQUIREMENTS,
|
|
&size, &buffer_requirements);
|
|
|
|
int32_t width = 256, height = 256;
|
|
|
|
VkImage rt;
|
|
vkCreateImage(device,
|
|
&(VkImageCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
|
.imageType = VK_IMAGE_TYPE_2D,
|
|
.format = VK_FORMAT_R8G8B8A8_UNORM,
|
|
.extent = { .width = width, .height = height, .depth = 1 },
|
|
.mipLevels = 1,
|
|
.arraySize = 1,
|
|
.samples = 1,
|
|
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
|
.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
|
|
.flags = 0,
|
|
},
|
|
&rt);
|
|
|
|
VkMemoryRequirements rt_requirements;
|
|
size = sizeof(rt_requirements);
|
|
vkGetObjectInfo(device, VK_OBJECT_TYPE_IMAGE, rt,
|
|
VK_OBJECT_INFO_TYPE_MEMORY_REQUIREMENTS,
|
|
&size, &rt_requirements);
|
|
|
|
VkBuffer vertex_buffer;
|
|
vkCreateBuffer(device,
|
|
&(VkBufferCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
|
.size = 1024,
|
|
.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
|
.flags = 0
|
|
},
|
|
&vertex_buffer);
|
|
|
|
VkMemoryRequirements vb_requirements;
|
|
size = sizeof(vb_requirements);
|
|
vkGetObjectInfo(device, VK_OBJECT_TYPE_BUFFER, vertex_buffer,
|
|
VK_OBJECT_INFO_TYPE_MEMORY_REQUIREMENTS,
|
|
&size, &vb_requirements);
|
|
|
|
VkBuffer image_buffer;
|
|
vkCreateBuffer(device,
|
|
&(VkBufferCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
|
.size = width * height * 4,
|
|
.usage = VK_BUFFER_USAGE_TRANSFER_DESTINATION_BIT,
|
|
.flags = 0
|
|
},
|
|
&image_buffer);
|
|
|
|
VkMemoryRequirements ib_requirements;
|
|
size = sizeof(ib_requirements);
|
|
vkGetObjectInfo(device, VK_OBJECT_TYPE_BUFFER, image_buffer,
|
|
VK_OBJECT_INFO_TYPE_MEMORY_REQUIREMENTS,
|
|
&size, &ib_requirements);
|
|
|
|
printf("buffer size: %lu, buffer alignment: %lu\n",
|
|
buffer_requirements.size, buffer_requirements.alignment);
|
|
printf("rt size: %lu, rt alignment: %lu\n",
|
|
rt_requirements.size, rt_requirements.alignment);
|
|
printf("vb size: %lu vb alignment: %lu\n",
|
|
vb_requirements.size, vb_requirements.alignment);
|
|
printf("ib size: %lu ib alignment: %lu\n",
|
|
ib_requirements.size, ib_requirements.alignment);
|
|
|
|
size_t mem_size = rt_requirements.size + ib_requirements.size +
|
|
2048 + 16 * 16 * 4;
|
|
VkDeviceMemory mem;
|
|
vkAllocMemory(device,
|
|
&(VkMemoryAllocInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO,
|
|
.allocationSize = mem_size,
|
|
.memProps = VK_MEMORY_PROPERTY_HOST_DEVICE_COHERENT_BIT,
|
|
.memPriority = VK_MEMORY_PRIORITY_NORMAL
|
|
},
|
|
&mem);
|
|
|
|
void *map;
|
|
vkMapMemory(device, mem, 0, mem_size, 0, &map);
|
|
memset(map, 192, mem_size);
|
|
|
|
vkQueueBindObjectMemory(queue, VK_OBJECT_TYPE_BUFFER,
|
|
buffer,
|
|
0, /* allocation index; for objects which need to bind to multiple mems */
|
|
mem, 128);
|
|
|
|
float color[12] = {
|
|
0.0, 0.2, 0.0, 0.0,
|
|
0.0, 0.0, 0.5, 0.0,
|
|
0.0, 0.0, 0.5, 0.5
|
|
};
|
|
memcpy(map + 128 + 16, color, sizeof(color));
|
|
VkBufferView buffer_view[3];
|
|
vkCreateBufferView(device,
|
|
&(VkBufferViewCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO,
|
|
.buffer = buffer,
|
|
.viewType = VK_BUFFER_VIEW_TYPE_RAW,
|
|
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
|
|
.offset = 16,
|
|
.range = 64
|
|
},
|
|
&buffer_view[0]);
|
|
|
|
vkCreateBufferView(device,
|
|
&(VkBufferViewCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO,
|
|
.buffer = buffer,
|
|
.viewType = VK_BUFFER_VIEW_TYPE_RAW,
|
|
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
|
|
.offset = 32,
|
|
.range = 64
|
|
},
|
|
&buffer_view[1]);
|
|
|
|
vkCreateBufferView(device,
|
|
&(VkBufferViewCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO,
|
|
.buffer = buffer,
|
|
.viewType = VK_BUFFER_VIEW_TYPE_RAW,
|
|
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
|
|
.offset = 48,
|
|
.range = 64
|
|
},
|
|
&buffer_view[2]);
|
|
|
|
vkQueueBindObjectMemory(queue, VK_OBJECT_TYPE_BUFFER,
|
|
vertex_buffer,
|
|
0, /* allocation index; for objects which need to bind to multiple mems */
|
|
mem, 1024);
|
|
static const float vertex_data[] = {
|
|
/* Triangle coordinates */
|
|
-0.5, -0.5, 0.0, 1.0,
|
|
0.5, -0.5, 0.0, 1.0,
|
|
0.0, 0.5, 0.0, 1.0,
|
|
/* Color */
|
|
1.0, 0.0, 0.0, 0.2,
|
|
};
|
|
memcpy(map + 1024, vertex_data, sizeof(vertex_data));
|
|
|
|
VkDynamicVpState vp_state;
|
|
vkCreateDynamicViewportState(device,
|
|
&(VkDynamicVpStateCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_DYNAMIC_VP_STATE_CREATE_INFO,
|
|
.viewportAndScissorCount = 2,
|
|
.pViewports = (VkViewport[]) {
|
|
{
|
|
.originX = 0,
|
|
.originY = 0,
|
|
.width = width,
|
|
.height = height,
|
|
.minDepth = 0,
|
|
.maxDepth = 1
|
|
},
|
|
{
|
|
.originX = -10,
|
|
.originY = -10,
|
|
.width = 20,
|
|
.height = 20,
|
|
.minDepth = -1,
|
|
.maxDepth = 1
|
|
},
|
|
},
|
|
.pScissors = (VkRect[]) {
|
|
{ { 0, 0 }, { width, height } },
|
|
{ { 10, 10 }, { 236, 236 } }
|
|
}
|
|
},
|
|
&vp_state);
|
|
|
|
VkDynamicRsState rs_state;
|
|
vkCreateDynamicRasterState(device,
|
|
&(VkDynamicRsStateCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_DYNAMIC_RS_STATE_CREATE_INFO,
|
|
},
|
|
&rs_state);
|
|
|
|
VkDynamicCbState cb_state;
|
|
vkCreateDynamicColorBlendState(device,
|
|
&(VkDynamicCbStateCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_DYNAMIC_CB_STATE_CREATE_INFO
|
|
},
|
|
&cb_state);
|
|
|
|
/* FIXME: Need to query memory info before binding to memory */
|
|
vkQueueBindObjectMemory(queue, VK_OBJECT_TYPE_IMAGE,
|
|
rt,
|
|
0, /* allocation index; for objects which need to bind to multiple mems */
|
|
mem, 2048);
|
|
|
|
vkQueueBindObjectMemory(queue, VK_OBJECT_TYPE_BUFFER,
|
|
image_buffer,
|
|
0, /* allocation index; for objects which need to bind to multiple mems */
|
|
mem, 2048 + rt_requirements.size);
|
|
|
|
const uint32_t texture_width = 16, texture_height = 16;
|
|
VkImage texture;
|
|
vkCreateImage(device,
|
|
&(VkImageCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
|
.imageType = VK_IMAGE_TYPE_2D,
|
|
.format = VK_FORMAT_R8G8B8A8_UNORM,
|
|
.extent = { .width = texture_width, .height = texture_height, .depth = 1 },
|
|
.mipLevels = 1,
|
|
.arraySize = 1,
|
|
.samples = 1,
|
|
.tiling = VK_IMAGE_TILING_LINEAR,
|
|
.usage = VK_IMAGE_USAGE_SAMPLED_BIT,
|
|
.flags = 0,
|
|
},
|
|
&texture);
|
|
|
|
vkQueueBindObjectMemory(queue, VK_OBJECT_TYPE_IMAGE,
|
|
texture,
|
|
0, /* allocation index; for objects which need to bind to multiple mems */
|
|
mem, 2048 + 256 * 256 * 4);
|
|
|
|
VkImageView image_view;
|
|
vkCreateImageView(device,
|
|
&(VkImageViewCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
|
.image = texture,
|
|
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
|
.format = VK_FORMAT_R8G8B8A8_UNORM,
|
|
.channels = {
|
|
VK_CHANNEL_SWIZZLE_R,
|
|
VK_CHANNEL_SWIZZLE_G,
|
|
VK_CHANNEL_SWIZZLE_B,
|
|
VK_CHANNEL_SWIZZLE_A
|
|
},
|
|
.subresourceRange = {
|
|
.aspect = VK_IMAGE_ASPECT_COLOR,
|
|
.baseMipLevel = 0,
|
|
.mipLevels = 1,
|
|
.baseArraySlice = 0,
|
|
.arraySize = 1
|
|
},
|
|
.minLod = 0
|
|
},
|
|
&image_view);
|
|
|
|
VkSampler sampler;
|
|
vkCreateSampler(device,
|
|
&(VkSamplerCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
|
|
.magFilter = VK_TEX_FILTER_LINEAR,
|
|
.minFilter = VK_TEX_FILTER_LINEAR,
|
|
.mipMode = VK_TEX_MIPMAP_MODE_NEAREST,
|
|
.addressU = VK_TEX_ADDRESS_CLAMP,
|
|
.addressV = VK_TEX_ADDRESS_CLAMP,
|
|
.addressW = VK_TEX_ADDRESS_CLAMP,
|
|
.mipLodBias = 0,
|
|
.maxAnisotropy = 0,
|
|
.compareOp = VK_COMPARE_OP_GREATER,
|
|
.minLod = 0,
|
|
.maxLod = 0,
|
|
.borderColor = VK_BORDER_COLOR_TRANSPARENT_BLACK
|
|
},
|
|
&sampler);
|
|
|
|
vkUpdateDescriptors(device, set[0], 3,
|
|
(const void * []) {
|
|
&(VkUpdateBuffers) {
|
|
.sType = VK_STRUCTURE_TYPE_UPDATE_BUFFERS,
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
.arrayIndex = 0,
|
|
.binding = 0,
|
|
.count = 2,
|
|
.pBufferViews = (VkBufferViewAttachInfo[]) {
|
|
{
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_ATTACH_INFO,
|
|
.view = buffer_view[0]
|
|
},
|
|
{
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_ATTACH_INFO,
|
|
.view = buffer_view[1]
|
|
}
|
|
}
|
|
},
|
|
&(VkUpdateImages) {
|
|
.sType = VK_STRUCTURE_TYPE_UPDATE_IMAGES,
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
|
|
.binding = 2,
|
|
.count = 1,
|
|
.pImageViews = (VkImageViewAttachInfo[]) {
|
|
{
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_ATTACH_INFO,
|
|
.view = image_view,
|
|
.layout = VK_IMAGE_LAYOUT_GENERAL,
|
|
}
|
|
}
|
|
},
|
|
&(const VkUpdateSamplers) {
|
|
.sType = VK_STRUCTURE_TYPE_UPDATE_SAMPLERS,
|
|
.binding = 3,
|
|
.count = 1,
|
|
.pSamplers = (const VkSampler[]) { sampler }
|
|
}
|
|
});
|
|
|
|
vkUpdateDescriptors(device, set[1], 1,
|
|
(const void * []) {
|
|
&(VkUpdateBuffers) {
|
|
.sType = VK_STRUCTURE_TYPE_UPDATE_BUFFERS,
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
.arrayIndex = 0,
|
|
.count = 1,
|
|
.pBufferViews = (VkBufferViewAttachInfo[]) {
|
|
{
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_ATTACH_INFO,
|
|
.view = buffer_view[2]
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
VkColorAttachmentView view;
|
|
vkCreateColorAttachmentView(device,
|
|
&(VkColorAttachmentViewCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_COLOR_ATTACHMENT_VIEW_CREATE_INFO,
|
|
.image = rt,
|
|
.format = VK_FORMAT_R8G8B8A8_UNORM,
|
|
.mipLevel = 0,
|
|
.baseArraySlice = 0,
|
|
.arraySize = 1,
|
|
.msaaResolveImage = 0,
|
|
.msaaResolveSubResource = { 0, }
|
|
},
|
|
&view);
|
|
|
|
VkFramebuffer framebuffer;
|
|
vkCreateFramebuffer(device,
|
|
&(VkFramebufferCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
|
.colorAttachmentCount = 1,
|
|
.pColorAttachments = (VkColorAttachmentBindInfo[]) {
|
|
{
|
|
.view = view,
|
|
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
|
|
}
|
|
},
|
|
.pDepthStencilAttachment = NULL,
|
|
.sampleCount = 1,
|
|
.width = width,
|
|
.height = height,
|
|
.layers = 1
|
|
},
|
|
&framebuffer);
|
|
|
|
VkRenderPass pass;
|
|
vkCreateRenderPass(device,
|
|
&(VkRenderPassCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
|
|
.renderArea = { { 0, 0 }, { width, height } },
|
|
.colorAttachmentCount = 1,
|
|
.extent = { },
|
|
.sampleCount = 1,
|
|
.layers = 1,
|
|
.pColorFormats = (VkFormat[]) { VK_FORMAT_R8G8B8A8_UNORM },
|
|
.pColorLayouts = (VkImageLayout[]) { VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL },
|
|
.pColorLoadOps = (VkAttachmentLoadOp[]) { VK_ATTACHMENT_LOAD_OP_CLEAR },
|
|
.pColorStoreOps = (VkAttachmentStoreOp[]) { VK_ATTACHMENT_STORE_OP_STORE },
|
|
.pColorLoadClearValues = (VkClearColor[]) {
|
|
{ .color = { .floatColor = { 1.0, 0.0, 0.0, 1.0 } }, .useRawValue = false }
|
|
},
|
|
.depthStencilFormat = VK_FORMAT_UNDEFINED,
|
|
},
|
|
&pass);
|
|
|
|
VkQueryPool query_pool;
|
|
vkCreateQueryPool(device,
|
|
&(VkQueryPoolCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,
|
|
.queryType = VK_QUERY_TYPE_OCCLUSION,
|
|
.slots = 4,
|
|
.pipelineStatistics = 0
|
|
},
|
|
&query_pool);
|
|
|
|
vkBeginCommandBuffer(cmdBuffer,
|
|
&(VkCmdBufferBeginInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO,
|
|
.flags = 0
|
|
});
|
|
|
|
vkCmdBeginRenderPass(cmdBuffer,
|
|
&(VkRenderPassBegin) {
|
|
.renderPass = pass,
|
|
.framebuffer = framebuffer
|
|
});
|
|
|
|
vkCmdBindVertexBuffers(cmdBuffer, 0, 2,
|
|
(VkBuffer[]) { vertex_buffer, vertex_buffer },
|
|
(VkDeviceSize[]) { 0, 3 * 4 * sizeof(float) });
|
|
|
|
vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
|
|
|
vkCmdBindDescriptorSets(cmdBuffer,
|
|
VK_PIPELINE_BIND_POINT_GRAPHICS, 0, 1,
|
|
&set[0], 0, NULL);
|
|
vkCmdBindDescriptorSets(cmdBuffer,
|
|
VK_PIPELINE_BIND_POINT_GRAPHICS, 1, 1,
|
|
&set[1], 0, NULL);
|
|
|
|
vkCmdBindDynamicStateObject(cmdBuffer,
|
|
VK_STATE_BIND_POINT_VIEWPORT, vp_state);
|
|
vkCmdBindDynamicStateObject(cmdBuffer,
|
|
VK_STATE_BIND_POINT_RASTER, rs_state);
|
|
vkCmdBindDynamicStateObject(cmdBuffer,
|
|
VK_STATE_BIND_POINT_COLOR_BLEND, cb_state);
|
|
|
|
vkCmdBeginQuery(cmdBuffer, query_pool, 0 /*slot*/, 0 /* flags */);
|
|
|
|
vkCmdDraw(cmdBuffer, 0, 3, 0, 1);
|
|
|
|
vkCmdEndQuery(cmdBuffer, query_pool, 0);
|
|
|
|
vkCmdEndRenderPass(cmdBuffer, pass);
|
|
|
|
vkCmdCopyQueryPoolResults(cmdBuffer, query_pool, 0, 1, buffer, 16, 8,
|
|
VK_QUERY_RESULT_WAIT_BIT | VK_QUERY_RESULT_64_BIT);
|
|
|
|
VkBufferImageCopy copy = {
|
|
.bufferOffset = 0,
|
|
.imageSubresource = {
|
|
.aspect = VK_IMAGE_ASPECT_COLOR,
|
|
.mipLevel = 0,
|
|
.arraySlice = 0,
|
|
},
|
|
.imageOffset = { .x = 0, .y = 0, .z = 0 },
|
|
.imageExtent = { .width = width, .height = height, .depth = 1 },
|
|
};
|
|
|
|
vkCmdCopyImageToBuffer(cmdBuffer, rt, VK_IMAGE_LAYOUT_GENERAL,
|
|
image_buffer, 1, ©);
|
|
|
|
vkEndCommandBuffer(cmdBuffer);
|
|
|
|
vkQueueSubmit(queue, 1, &cmdBuffer, 0);
|
|
|
|
vkQueueWaitIdle(queue);
|
|
|
|
/* Result gets written to buffer at offset 0. The buffer is bound to the
|
|
* memory object at offset 128 */
|
|
uint64_t *results = map + 128;
|
|
|
|
uint64_t get_result;
|
|
size = sizeof(get_result);
|
|
vkGetQueryPoolResults(device, query_pool, 0, 1, &size, &get_result,
|
|
VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
|
|
|
|
printf("oc query (copy): %20ld (%016lx)\n", results[2], results[2]);
|
|
printf("oc query (get): %20ld (%016lx)\n", get_result, get_result);
|
|
|
|
write_png("vk-map.png", width, height, 1024, map + 2048);
|
|
write_png("vk-copy.png", width, height, 1024,
|
|
map + 2048 + rt_requirements.size);
|
|
|
|
vkDestroyObject(device, VK_OBJECT_TYPE_IMAGE, texture);
|
|
vkDestroyObject(device, VK_OBJECT_TYPE_IMAGE, rt);
|
|
vkDestroyObject(device, VK_OBJECT_TYPE_BUFFER, buffer);
|
|
vkDestroyObject(device, VK_OBJECT_TYPE_COMMAND_BUFFER, cmdBuffer);
|
|
vkDestroyObject(device, VK_OBJECT_TYPE_PIPELINE, pipeline);
|
|
vkDestroyObject(device, VK_OBJECT_TYPE_QUERY_POOL, query_pool);
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
VkInstance instance;
|
|
vkCreateInstance(&(VkInstanceCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
|
.pAllocCb = &(VkAllocCallbacks) {
|
|
.pUserData = NULL,
|
|
.pfnAlloc = test_alloc,
|
|
.pfnFree = test_free
|
|
},
|
|
.pAppInfo = &(VkApplicationInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
|
.pAppName = "vk",
|
|
.apiVersion = 1
|
|
}
|
|
},
|
|
&instance);
|
|
|
|
uint32_t count = 1;
|
|
VkPhysicalDevice physicalDevices[1];
|
|
vkEnumeratePhysicalDevices(instance, &count, physicalDevices);
|
|
printf("%d physical devices\n", count);
|
|
|
|
VkPhysicalDeviceProperties properties;
|
|
size_t size = sizeof(properties);
|
|
vkGetPhysicalDeviceInfo(physicalDevices[0],
|
|
VK_PHYSICAL_DEVICE_INFO_TYPE_PROPERTIES,
|
|
&size, &properties);
|
|
printf("vendor id %04x, device name %s\n",
|
|
properties.vendorId, properties.deviceName);
|
|
|
|
VkDevice device;
|
|
vkCreateDevice(physicalDevices[0],
|
|
&(VkDeviceCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
|
.queueRecordCount = 1,
|
|
.pRequestedQueues = &(VkDeviceQueueCreateInfo) {
|
|
.queueNodeIndex = 0,
|
|
.queueCount = 1
|
|
}
|
|
},
|
|
&device);
|
|
|
|
VkQueue queue;
|
|
vkGetDeviceQueue(device, 0, 0, &queue);
|
|
|
|
if (argc > 1 && strcmp(argv[1], "timestamp") == 0) {
|
|
test_timestamp(device, queue);
|
|
} else if (argc > 1 && strcmp(argv[1], "formats") == 0) {
|
|
test_formats(device, queue);
|
|
} else if (argc > 1 && strcmp(argv[1], "buffer-copy") == 0) {
|
|
test_buffer_copy(device, queue);
|
|
} else if (argc > 1 && strcmp(argv[1], "depth-stencil") == 0) {
|
|
test_depth_stencil(device, queue);
|
|
} else {
|
|
test_triangle(device, queue);
|
|
}
|
|
|
|
vkDestroyDevice(device);
|
|
|
|
vkDestroyInstance(instance);
|
|
|
|
return 0;
|
|
}
|