diff --git a/driver/command.c b/driver/command.c index ea5f4da..a0af51c 100644 --- a/driver/command.c +++ b/driver/command.c @@ -146,6 +146,7 @@ VKAPI_ATTR VkResult VKAPI_CALL rpi_vkAllocateCommandBuffers( pCommandBuffers[c]->stencilReferenceDirty = 1; pCommandBuffers[c]->descriptorSetDirty = 1; pCommandBuffers[c]->pushConstantDirty = 1; + pCommandBuffers[c]->currRenderPass = 0; pCommandBuffers[c]->perfmonID = 0; @@ -854,6 +855,7 @@ VKAPI_ATTR VkResult VKAPI_CALL rpi_vkResetCommandBuffer( commandBuffer->stencilReferenceDirty = 1; commandBuffer->descriptorSetDirty = 1; commandBuffer->pushConstantDirty = 1; + commandBuffer->currRenderPass = 0; commandBuffer->perfmonID = 0; } diff --git a/driver/common.h b/driver/common.h index 84eb2d7..eebf42d 100644 --- a/driver/common.h +++ b/driver/common.h @@ -137,12 +137,14 @@ typedef struct VkDevice_T VkDescriptorPool emulDescriptorPool; VkDescriptorSetLayout emulBufferDsl; VkDescriptorSetLayout emulTextureDsl; + VkDescriptorSetLayout emulClearDsl; VkSampler emulNearestTextureSampler; VkSampler emulLinearTextureSampler; VkShaderModule emulBufferToTextureShaderModule; VkShaderModule emulTextureToTextureShaderModule; VkShaderModule emulTextureToBufferShaderModule; //TODO VkShaderModule emulBufferToBufferShaderModule; //TODO + VkShaderModule emulClearShaderModule; } _device; typedef struct VkRenderPass_T @@ -350,6 +352,8 @@ typedef struct VkCommandBuffer_T _pipeline* graphicsPipeline; _pipeline* computePipeline; + _renderpass* currRenderPass; + uint32_t numDrawCallsSubmitted; VkViewport viewport; @@ -553,4 +557,5 @@ uint32_t getRenderTargetFormatVC4(VkFormat format); void clFit(VkCommandBuffer cb, ControlList* cl, uint32_t commandSize); void clDump(void* cl, uint32_t size); void setupEmulationResources(VkDevice device); +void setupClearEmulationResources(VkDevice device); uint32_t getPow2Pad(uint32_t n); diff --git a/driver/device.c b/driver/device.c index b075c20..cd0eeb6 100644 --- a/driver/device.c +++ b/driver/device.c @@ -320,6 +320,7 @@ VKAPI_ATTR VkResult VKAPI_CALL rpi_vkCreateDevice( } setupEmulationResources(*pDevice); + setupClearEmulationResources(*pDevice); return VK_SUCCESS; } diff --git a/driver/draw.c b/driver/draw.c index 16cb780..2eca1e2 100644 --- a/driver/draw.c +++ b/driver/draw.c @@ -139,6 +139,10 @@ static uint32_t drawCommon(VkCommandBuffer commandBuffer, int32_t vertexOffset) vertModule = cb->graphicsPipeline->modules[ulog2(VK_SHADER_STAGE_VERTEX_BIT)]; } +// fprintf(stderr, "==============\n", fragModule); +// fprintf(stderr, "fragModule %p\n", fragModule); +// fprintf(stderr, "vertModule %p\n", vertModule); + if(!vertModule) { vertModule = fragModule; @@ -149,6 +153,15 @@ static uint32_t drawCommon(VkCommandBuffer commandBuffer, int32_t vertexOffset) fragModule = vertModule; } +// fprintf(stderr, "fragModule %p\n", fragModule); +// fprintf(stderr, "vertModule %p\n", vertModule); + + assert(fragModule); + assert(vertModule); + assert(fragModule->bos[VK_RPI_ASSEMBLY_TYPE_FRAGMENT]); + assert(vertModule->bos[VK_RPI_ASSEMBLY_TYPE_VERTEX]); + assert(vertModule->bos[VK_RPI_ASSEMBLY_TYPE_COORDINATE]); + //emit shader record ControlListAddress fragCode = { .handle = fragModule->bos[VK_RPI_ASSEMBLY_TYPE_FRAGMENT], diff --git a/driver/renderpass.c b/driver/renderpass.c index d962c42..1f31513 100644 --- a/driver/renderpass.c +++ b/driver/renderpass.c @@ -278,6 +278,8 @@ void rpi_vkCmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassB clInsertStartTileBinning(&commandBuffer->binCl); cb->binCl.currMarker->perfmonID = cb->perfmonID; + + cb->currRenderPass = rp; } /* @@ -300,6 +302,8 @@ void rpi_vkCmdEndRenderPass(VkCommandBuffer commandBuffer) clInsertIncrementSemaphore(&cb->binCl); clFit(commandBuffer, &cb->binCl, V3D21_FLUSH_length); clInsertFlush(&cb->binCl); + + cb->currRenderPass = 0; } /* diff --git a/driver/shader.c b/driver/shader.c index 175a686..041364b 100644 --- a/driver/shader.c +++ b/driver/shader.c @@ -103,6 +103,7 @@ VkResult rpi_vkCreateShaderModule(VkDevice device, const VkShaderModuleCreateInf /**/ shader->bos[c] = vc4_bo_alloc_shader(controlFd, ci->instructions[c], &shader->sizes[c]); + assert(shader->bos[c]); } else { @@ -135,6 +136,10 @@ VkResult rpi_vkCreateShaderModule(VkDevice device, const VkShaderModuleCreateInf assert(hadVertex == hadCoordinate); +// fprintf(stderr, "pixel shader bo %i\n", shader->bos[2]); +// fprintf(stderr, "vertex shader bo %i\n", shader->bos[1]); +// fprintf(stderr, "coord shader bo %i\n", shader->bos[0]); + *pShaderModule = shader; return VK_SUCCESS; diff --git a/driver/stateChange.c b/driver/stateChange.c index ea79e49..81f4cb5 100644 --- a/driver/stateChange.c +++ b/driver/stateChange.c @@ -2,6 +2,400 @@ #include "kernel/vc4_packet.h" +#include "declarations.h" + +#include "QPUassembler/qpu_assembler.h" + +void createClearShaderModule(VkDevice device, VkShaderModule* blitShaderModule) +{ + char vs_asm_code[] = + ///0x40000000 = 2.0 + ///uni = 1.0 + ///rb0 = 2 - 1 = 1 + "sig_small_imm ; rx0 = fsub.ws.always(b, a, uni, 0x40000000) ; nop = nop(r0, r0) ;\n" + ///set up VPM read for subsequent reads + ///0x00201a00: 0000 0000 0010 0000 0001 1010 0000 0000 + ///addr: 0 + ///size: 32bit + ///packed + ///horizontal + ///stride=1 + ///vectors to read = 2 (how many components) + "sig_load_imm ; vr_setup = load32.always(0x00201a00) ; nop = load32.always() ;\n" + ///uni = viewportXScale + ///r0 = vpm * uni + "sig_none ; nop = nop(r0, r0, vpm_read, uni) ; r0 = fmul.always(a, b) ;\n" + ///r1 = r0 * rb0 (1) + "sig_none ; nop = nop(r0, r0, nop, rb0) ; r1 = fmul.always(r0, b) ;\n" + ///uni = viewportYScale + ///ra0.16a = int(r1), r2 = vpm * uni + "sig_none ; rx0.16a = ftoi.always(r1, r1, vpm_read, uni) ; r2 = fmul.always(a, b) ;\n" + ///r3 = r2 * rb0 + "sig_none ; nop = nop(r0, r0, nop, rb0) ; r3 = fmul.always(r2, b) ;\n" + ///ra0.16b = int(r3) + "sig_none ; rx0.16b = ftoi.always(r3, r3) ; nop = nop(r0, r0) ;\n" + ///set up VPM write for subsequent writes + ///0x00001a00: 0000 0000 0000 0000 0001 1010 0000 0000 + ///addr: 0 + ///size: 32bit + ///horizontal + ///stride = 1 + "sig_load_imm ; vw_setup = load32.always.ws(0x00001a00) ; nop = load32.always() ;\n" + ///shaded vertex format for PSE + /// Ys and Xs + ///vpm = ra0 + "sig_none ; vpm = or.always(a, a, ra0, nop) ; nop = nop(r0, r0);\n" + /// Zs + ///uni = 0.5 + ///vpm = uni + "sig_none ; vpm = or.always(a, a, uni, nop) ; nop = nop(r0, r0);\n" + /// 1.0 / Wc + ///vpm = rb0 (1) + "sig_none ; vpm = or.always(b, b, nop, rb0) ; nop = nop(r0, r0);\n" + ///END + "sig_end ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;\n" + "sig_none ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;\n" + "sig_none ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;\n" + "\0"; + + char cs_asm_code[] = + ///uni = 1.0 + ///r3 = 2.0 - uni + "sig_small_imm ; r3 = fsub.always(b, a, uni, 0x40000000) ; nop = nop(r0, r0);\n" + "sig_load_imm ; vr_setup = load32.always(0x00201a00) ; nop = load32.always() ;\n" + ///r2 = vpm + "sig_none ; r2 = or.always(a, a, vpm_read, nop) ; nop = nop(r0, r0);\n" + "sig_load_imm ; vw_setup = load32.always.ws(0x00001a00) ; nop = load32.always() ;\n" + ///shaded coordinates format for PTB + /// write Xc + ///r1 = vpm, vpm = r2 + "sig_none ; r1 = or.always(a, a, vpm_read, nop) ; vpm = v8min.always(r2, r2);\n" + /// write Yc + ///uni = viewportXscale + ///vpm = r1, r2 = r2 * uni + "sig_none ; vpm = or.always(r1, r1, uni, nop) ; r2 = fmul.always(r2, a);\n" + ///uni = viewportYscale + ///r1 = r1 * uni + "sig_none ; nop = nop(r0, r0, uni, nop) ; r1 = fmul.always(r1, a);\n" + ///r0 = r2 * r3 + "sig_none ; nop = nop(r0, r0) ; r0 = fmul.always(r2, r3);\n" + ///ra0.16a = r0, r1 = r1 * r3 + "sig_none ; rx0.16a = ftoi.always(r0, r0) ; r1 = fmul.always(r1, r3) ;\n" + ///ra0.16b = r1 + "sig_none ; rx0.16b = ftoi.always(r1, r1) ; nop = nop(r0, r0) ;\n" + ///write Zc + ///vpm = 0 + "sig_small_imm ; vpm = or.always(b, b, nop, 0) ; nop = nop(r0, r0) ;\n" + ///write Wc + ///vpm = 1.0 + "sig_small_imm ; vpm = or.always(b, b, nop, 0x3f800000) ; nop = nop(r0, r0) ;\n" + ///write Ys and Xs + ///vpm = ra0 + "sig_none ; vpm = or.always(a, a, ra0, nop) ; nop = nop(r0, r0) ;\n" + ///write Zs + ///uni = 0.5 + ///vpm = uni + "sig_none ; vpm = or.always(a, a, uni, nop) ; nop = nop(r0, r0) ;\n" + ///write 1/Wc + ///vpm = r3 + "sig_none ; vpm = or.always(r3, r3) ; nop = nop(r0, r0) ;\n" + ///END + "sig_end ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;\n" + "sig_none ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;\n" + "sig_none ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;\n" + "\0"; + + //sample texture + char fs_asm_code[] = + "sig_none ; r0 = or.always(a, a, uni, nop) ; nop = nop(r0, r0) ;" //clear color value + "sig_none ; r1 = or.always(a, a, uni, nop) ; nop = nop(r0, r0) ;" //stencil setup + "sig_none ; r2 = or.always(a, a, uni, nop) ; nop = nop(r0, r0) ;" //depth clear value + "sig_none ; tlb_stencil_setup = or.always(r1, r1) ; nop = nop(r0, r0) ;" + "sig_none ; tlb_z = or.always(r2, r2) ; nop = nop(r0, r0) ;" + "sig_none ; tlb_color_all = or.always(r0, r0) ; nop = nop(r0, r0) ;" + "sig_end ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;" + "sig_none ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;" + "sig_unlock_score ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;" + "\0"; + + char* blit_asm_strings[] = + { + (char*)cs_asm_code, (char*)vs_asm_code, (char*)fs_asm_code, 0 + }; + + VkRpiAssemblyMappingEXT vertexMappings[] = { + //vertex shader uniforms + { + VK_RPI_ASSEMBLY_MAPPING_TYPE_PUSH_CONSTANT, + VK_DESCRIPTOR_TYPE_MAX_ENUM, //descriptor type + 0, //descriptor set # + 0, //descriptor binding # + 0, //descriptor array element # + 0, //resource offset + }, + { + VK_RPI_ASSEMBLY_MAPPING_TYPE_PUSH_CONSTANT, + VK_DESCRIPTOR_TYPE_MAX_ENUM, //descriptor type + 0, //descriptor set # + 0, //descriptor binding # + 0, //descriptor array element # + 4, //resource offset + }, + { + VK_RPI_ASSEMBLY_MAPPING_TYPE_PUSH_CONSTANT, + VK_DESCRIPTOR_TYPE_MAX_ENUM, //descriptor type + 0, //descriptor set # + 0, //descriptor binding # + 0, //descriptor array element # + 8, //resource offset + }, + { + VK_RPI_ASSEMBLY_MAPPING_TYPE_PUSH_CONSTANT, + VK_DESCRIPTOR_TYPE_MAX_ENUM, //descriptor type + 0, //descriptor set # + 0, //descriptor binding # + 0, //descriptor array element # + 12, //resource offset + }, + }; + + VkRpiAssemblyMappingEXT fragmentMappings[] = { + //fragment shader uniforms + { + VK_RPI_ASSEMBLY_MAPPING_TYPE_PUSH_CONSTANT, + VK_DESCRIPTOR_TYPE_MAX_ENUM, //descriptor type + 0, //descriptor set # + 0, //descriptor binding # + 0, //descriptor array element # + 0, //resource offset + }, + { + VK_RPI_ASSEMBLY_MAPPING_TYPE_PUSH_CONSTANT, + VK_DESCRIPTOR_TYPE_MAX_ENUM, //descriptor type + 0, //descriptor set # + 0, //descriptor binding # + 0, //descriptor array element # + 4, //resource offset + }, + { + VK_RPI_ASSEMBLY_MAPPING_TYPE_PUSH_CONSTANT, + VK_DESCRIPTOR_TYPE_MAX_ENUM, //descriptor type + 0, //descriptor set # + 0, //descriptor binding # + 0, //descriptor array element # + 8, //resource offset + }, + + }; + + uint32_t spirv[6]; + + uint64_t* asm_ptrs[4] = {}; + uint32_t asm_sizes[4] = {}; + + VkRpiAssemblyMappingEXT* asm_mappings[4] = {}; + uint32_t asm_mappings_sizes[4] = {}; + + VkRpiShaderModuleAssemblyCreateInfoEXT shaderModuleCreateInfo = {}; + shaderModuleCreateInfo.instructions = asm_ptrs; + shaderModuleCreateInfo.numInstructions = asm_sizes; + shaderModuleCreateInfo.mappings = asm_mappings; + shaderModuleCreateInfo.numMappings = asm_mappings_sizes; + + asm_mappings[VK_RPI_ASSEMBLY_TYPE_VERTEX] = vertexMappings; + asm_mappings_sizes[VK_RPI_ASSEMBLY_TYPE_VERTEX] = sizeof(vertexMappings) / sizeof(VkRpiAssemblyMappingEXT); + asm_mappings[VK_RPI_ASSEMBLY_TYPE_FRAGMENT] = fragmentMappings; + asm_mappings_sizes[VK_RPI_ASSEMBLY_TYPE_FRAGMENT] = sizeof(fragmentMappings) / sizeof(VkRpiAssemblyMappingEXT); + + //TODO use allocator + + { //assemble cs code + asm_sizes[0] = get_num_instructions(cs_asm_code); + uint32_t size = sizeof(uint64_t)*asm_sizes[0]; + //TODO this alloc feels kinda useless, we just copy the data anyway to kernel space + //why not map kernel space mem to user space instead? + asm_ptrs[0] = (uint64_t*)malloc(size); + assemble_qpu_asm(cs_asm_code, asm_ptrs[0]); + assert(asm_ptrs[0]); + } + + { //assemble vs code + asm_sizes[1] = get_num_instructions(vs_asm_code); + uint32_t size = sizeof(uint64_t)*asm_sizes[1]; + //TODO this alloc feels kinda useless, we just copy the data anyway to kernel space + //why not map kernel space mem to user space instead? + asm_ptrs[1] = (uint64_t*)malloc(size); + assemble_qpu_asm(vs_asm_code, asm_ptrs[1]); + assert(asm_ptrs[1]); + } + + { //assemble fs code + asm_sizes[2] = get_num_instructions(fs_asm_code); + uint32_t size = sizeof(uint64_t)*asm_sizes[2]; + //TODO this alloc feels kinda useless, we just copy the data anyway to kernel space + //why not map kernel space mem to user space instead? + asm_ptrs[2] = (uint64_t*)malloc(size); + assemble_qpu_asm(fs_asm_code, asm_ptrs[2]); + assert(asm_ptrs[2]); + } + + spirv[0] = 0x07230203; + spirv[1] = 0x00010000; + spirv[2] = 0x14E45250; + spirv[3] = 1; + spirv[4] = (uint32_t)&shaderModuleCreateInfo; + //words start here + spirv[5] = 1 << 16; + + VkShaderModuleCreateInfo smci = {}; + smci.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + smci.codeSize = sizeof(uint32_t)*6; + smci.pCode = spirv; + rpi_vkCreateShaderModule(device, &smci, 0, blitShaderModule); + assert(*blitShaderModule); + +// _shaderModule* s = *blitShaderModule; +// fprintf(stderr, "=================\n"); +// fprintf(stderr, "pixel shader bo %i\n", s->bos[2]); +// fprintf(stderr, "vertex shader bo %i\n", s->bos[1]); +// fprintf(stderr, "coord shader bo %i\n", s->bos[0]); + + for(uint32_t c = 0; c < 4; ++c) + { + free(asm_ptrs[c]); + } +} + +void createClearPipeline(VkDevice device, VkPipelineDepthStencilStateCreateInfo* dsState, VkShaderModule blitShaderModule, VkDescriptorSetLayout blitDsl, VkPipelineLayout* blitPipelineLayout, VkRenderPass offscreenRenderPass, VkPipeline* blitPipeline) +{ + VkVertexInputBindingDescription vertexInputBindingDescription = + { + 0, + sizeof(float) * 2 * 2, + VK_VERTEX_INPUT_RATE_VERTEX + }; + + VkVertexInputAttributeDescription vertexInputAttributeDescription[2]; + + { + vertexInputAttributeDescription[0].binding = 0; + vertexInputAttributeDescription[0].location = 0; + vertexInputAttributeDescription[0].offset = 0; + vertexInputAttributeDescription[0].format = VK_FORMAT_R32G32_SFLOAT; + } + + VkPipelineVertexInputStateCreateInfo vertexInputInfo = {}; + vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertexInputInfo.vertexAttributeDescriptionCount = 1; + vertexInputInfo.pVertexAttributeDescriptions = vertexInputAttributeDescription; + vertexInputInfo.vertexBindingDescriptionCount = 1; + vertexInputInfo.pVertexBindingDescriptions = &vertexInputBindingDescription; + + VkPipelineInputAssemblyStateCreateInfo pipelineIACreateInfo = {}; + pipelineIACreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + pipelineIACreateInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + + VkPipelineRasterizationStateCreateInfo rastCreateInfo = {}; + rastCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rastCreateInfo.polygonMode = VK_POLYGON_MODE_FILL; + rastCreateInfo.cullMode = VK_CULL_MODE_NONE; + rastCreateInfo.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rastCreateInfo.lineWidth = 1.0f; + + VkPipelineMultisampleStateCreateInfo pipelineMSCreateInfo = {}; + pipelineMSCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + + VkPipelineColorBlendAttachmentState blendAttachState = {}; + blendAttachState.colorWriteMask = 0xf; + blendAttachState.blendEnable = false; + + VkPipelineColorBlendStateCreateInfo blendCreateInfo = {}; + blendCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + blendCreateInfo.attachmentCount = 1; + blendCreateInfo.pAttachments = &blendAttachState; + + //create blit pipeline + VkPushConstantRange pushConstantRanges[2]; + pushConstantRanges[0].offset = 0; + pushConstantRanges[0].size = 4 * 4; //n * 32bits + pushConstantRanges[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + + pushConstantRanges[1].offset = 0; + pushConstantRanges[1].size = 3 * 4; //n * 32bits + pushConstantRanges[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + + VkPipelineShaderStageCreateInfo shaderStageCreateInfo[2] = {}; + + shaderStageCreateInfo[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shaderStageCreateInfo[0].stage = VK_SHADER_STAGE_VERTEX_BIT; + shaderStageCreateInfo[0].module = blitShaderModule; + shaderStageCreateInfo[0].pName = "main"; + shaderStageCreateInfo[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shaderStageCreateInfo[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; + shaderStageCreateInfo[1].module = blitShaderModule; + shaderStageCreateInfo[1].pName = "main"; + + VkPipelineLayoutCreateInfo pipelineLayoutCI = {}; + pipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutCI.setLayoutCount = 1; + pipelineLayoutCI.pSetLayouts = &blitDsl; + pipelineLayoutCI.pushConstantRangeCount = 2; + pipelineLayoutCI.pPushConstantRanges = &pushConstantRanges[0]; + rpi_vkCreatePipelineLayout(device, &pipelineLayoutCI, 0, blitPipelineLayout); + + VkDynamicState dynState = VK_DYNAMIC_STATE_VIEWPORT; + + VkPipelineDynamicStateCreateInfo pdsci = {}; + pdsci.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + pdsci.dynamicStateCount = 1; + pdsci.pDynamicStates = &dynState; + + VkPipelineViewportStateCreateInfo pvsci = {}; + pvsci.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + pvsci.viewportCount = 0; + pvsci.scissorCount = 0; + + VkGraphicsPipelineCreateInfo pipelineInfo = {}; + pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipelineInfo.stageCount = 2; + pipelineInfo.pStages = &shaderStageCreateInfo[0]; + pipelineInfo.pVertexInputState = &vertexInputInfo; + pipelineInfo.pInputAssemblyState = &pipelineIACreateInfo; + pipelineInfo.pViewportState = &pvsci; + pipelineInfo.pDynamicState = &pdsci; + pipelineInfo.pRasterizationState = &rastCreateInfo; + pipelineInfo.pMultisampleState = &pipelineMSCreateInfo; + pipelineInfo.pColorBlendState = &blendCreateInfo; + pipelineInfo.renderPass = offscreenRenderPass; + pipelineInfo.basePipelineIndex = -1; + pipelineInfo.pDepthStencilState = dsState; + pipelineInfo.layout = *blitPipelineLayout; + + VkResult res = rpi_vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, NULL, blitPipeline); +} + +void createClearDescriptorSetLayouts(VkDevice device, VkDescriptorSetLayout* bufferDsl) +{ + assert(device); + assert(bufferDsl); + + VkDescriptorSetLayoutCreateInfo descriptorLayoutCI = {}; + descriptorLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + descriptorLayoutCI.bindingCount = 0; + descriptorLayoutCI.pBindings = 0; + + rpi_vkCreateDescriptorSetLayout(device, &descriptorLayoutCI, 0, bufferDsl); +} + +void setupClearEmulationResources(VkDevice device) +{ + //create resources that won't change + _device* dev = device; + + createClearShaderModule(device, &dev->emulClearShaderModule); + createClearDescriptorSetLayouts(device, &dev->emulClearDsl); +} + /* * https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#vkCmdSetViewport */ @@ -173,7 +567,112 @@ VKAPI_ATTR void VKAPI_CALL rpi_vkCmdClearAttachments( assert(pAttachments); assert(pRects); - //TODO + _commandBuffer* cmdBuf = commandBuffer; + _device* device = cmdBuf->dev; + + if(!cmdBuf->currRenderPass) + { + //no active render pass + return; + } + + for(uint32_t c = 0; c < attachmentCount; ++c) + { + uint32_t clearColor = 0, clearDepth = 0, clearStencil = 0; + + if(pAttachments[c].aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) + { + clearColor = 1; + } + + if(pAttachments[c].aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) + { + clearDepth = 1; + } + + if(pAttachments[c].aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) + { + clearStencil = 1; + } + + VkPipeline blitPipeline; + VkPipelineLayout blitPipelineLayout; + + VkPipelineDepthStencilStateCreateInfo dsci = {}; + dsci.depthCompareOp = VK_COMPARE_OP_ALWAYS; + dsci.depthTestEnable = 1; + dsci.depthWriteEnable = clearDepth; + dsci.minDepthBounds = 0.0f; + dsci.maxDepthBounds = 1.0f; + dsci.stencilTestEnable = clearStencil; + dsci.front.compareMask = 0xff; + dsci.front.writeMask = 0xff; + dsci.front.reference = pAttachments[c].clearValue.depthStencil.stencil; + dsci.front.depthFailOp = VK_STENCIL_OP_REPLACE; + dsci.front.failOp = VK_STENCIL_OP_REPLACE; + dsci.front.passOp = VK_STENCIL_OP_REPLACE; + dsci.back = dsci.front; + + createClearPipeline(device, &dsci, device->emulClearShaderModule, device->emulClearDsl, &blitPipelineLayout, cmdBuf->currRenderPass, &blitPipeline); + +// _shaderModule* s = device->emulClearShaderModule; +// fprintf(stderr, "=================\n"); +// fprintf(stderr, "pixel shader bo %i\n", s->bos[2]); +// fprintf(stderr, "vertex shader bo %i\n", s->bos[1]); +// fprintf(stderr, "coord shader bo %i\n", s->bos[0]); + + rpi_vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, blitPipeline); + + VkDeviceSize offsets = 0; + rpi_vkCmdBindVertexBuffers(commandBuffer, 0, 1, &device->emulFsqVertexBuffer, &offsets ); + + uint32_t clearColorValue = 0, stencilSetup = 0, depthClearValue = 0; + + clearColorValue = packVec4IntoABGR8(&pAttachments[c].clearValue.color.float32[0]); + depthClearValue = (uint32_t)(pAttachments[c].clearValue.depthStencil.depth * 0xffffff) & 0xffffff; + uint32_t numValues = 1; + encodeStencilValue(&stencilSetup, &numValues, dsci.front, dsci.back, clearStencil); + + + uint32_t fragConstants[3]; + fragConstants[0] = clearColorValue; + fragConstants[1] = stencilSetup; + fragConstants[2] = depthClearValue; + + rpi_vkCmdPushConstants(commandBuffer, blitPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(fragConstants), &fragConstants); + + for(uint32_t d = 0; d < rectCount; ++d) + { + VkViewport vp = {}; + vp.x = pRects[d].rect.offset.x; + vp.y = pRects[d].rect.offset.y; + vp.width = pRects[d].rect.extent.width; + vp.height = pRects[d].rect.extent.height; + vp.minDepth = 0.0f; + vp.maxDepth = 1.0f; + + rpi_vkCmdSetViewport(commandBuffer, 0, 1, &vp); + + float Wcoeff = 1.0f; //1.0f / Wc = 2.0 - Wcoeff + float viewportScaleX = (float)(vp.width) * 0.5f * 16.0f; + float viewportScaleY = 1.0f * (float)(vp.height) * 0.5f * 16.0f; + float Zs = 1.0f; + + uint32_t vertConstants[4]; + vertConstants[0] = *(uint32_t*)&Wcoeff; + vertConstants[1] = *(uint32_t*)&viewportScaleX; + vertConstants[2] = *(uint32_t*)&viewportScaleY; + vertConstants[3] = *(uint32_t*)&Zs; + + rpi_vkCmdPushConstants(commandBuffer, blitPipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(vertConstants), &vertConstants); + + rpi_vkCmdDraw(commandBuffer, 6, 1, 0, 0); + } + + //free up resources + rpi_vkDestroyPipelineLayout(device, blitPipelineLayout, 0); + rpi_vkDestroyPipeline(device, blitPipeline, 0); + } } /* diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 5f3a19c..6af9cfe 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -14,4 +14,5 @@ add_subdirectory(query) add_subdirectory(mipmapping) add_subdirectory(CPAtest) add_subdirectory(cubemapping) -add_subdirectory(attribTest) \ No newline at end of file +add_subdirectory(attribTest) +add_subdirectory(clearTest) \ No newline at end of file diff --git a/test/clearTest/CMakeLists.txt b/test/clearTest/CMakeLists.txt new file mode 100644 index 0000000..9f9774d --- /dev/null +++ b/test/clearTest/CMakeLists.txt @@ -0,0 +1,9 @@ +file(GLOB testSrc + "*.h" + "*.cpp" +) + +add_executable(clearTest ${testSrc} ) +target_compile_options(clearTest PRIVATE -Wall -std=c++11 -std=c11) + +target_link_libraries(clearTest vulkan $) diff --git a/test/clearTest/clearTest.cpp b/test/clearTest/clearTest.cpp new file mode 100644 index 0000000..5a745b2 --- /dev/null +++ b/test/clearTest/clearTest.cpp @@ -0,0 +1,1491 @@ +#include +#include +#include +#include +#include "driver/CustomAssert.h" + +#include + +#include "driver/vkExt.h" +#include "QPUassembler/qpu_assembler.h" + +//#define GLFW_INCLUDE_VULKAN +//#define VK_USE_PLATFORM_WIN32_KHR +//#include + +//#define GLFW_EXPOSE_NATIVE_WIN32 +//#include + +//GLFWwindow * window; + +//#define WINDOW_WIDTH 640 +//#define WINDOW_HEIGHT 480 + +// Note: support swap chain recreation (not only required for resized windows!) +// Note: window resize may not result in Vulkan telling that the swap chain should be recreated, should be handled explicitly! +void run(); +void setupVulkan(); +void mainLoop(); +void cleanup(); +void createInstance(); +void createWindowSurface(); +void findPhysicalDevice(); +void checkSwapChainSupport(); +void findQueueFamilies(); +void createLogicalDevice(); +void createSemaphores(); +void createSwapChain(); +void createDepthBuffer(); +void createCommandQueues(); +void draw(); +void CreateRenderPass(); +void CreateFramebuffer(); +void CreateShaders(); +void CreatePipeline(); +void CreateUniformBuffer(); +void CreateDescriptorSet(); +void CreateVertexBuffer(); +void CreateTexture(); +void recordCommandBuffers(); +VkSurfaceFormatKHR chooseSurfaceFormat(const std::vector& availableFormats); +VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& surfaceCapabilities); +VkPresentModeKHR choosePresentMode(const std::vector presentModes); +uint32_t getMemoryTypeIndex(VkPhysicalDeviceMemoryProperties deviceMemoryProperties, uint32_t typeBits, VkMemoryPropertyFlags properties); + +VkInstance instance; // +VkSurfaceKHR windowSurface; // +VkPhysicalDevice physicalDevice; +VkDevice device; // +VkSemaphore imageAvailableSemaphore; // +VkSemaphore renderingFinishedSemaphore; // +VkSwapchainKHR swapChain; // +VkCommandPool commandPool; // +std::vector presentCommandBuffers; // +std::vector swapChainImages; // +VkRenderPass renderPass; // +std::vector fbs; // +VkShaderModule shaderModule; // +VkPipeline pipeline; // +VkQueue graphicsQueue; +VkQueue presentQueue; +VkBuffer vertexBuffer1; +VkDeviceMemory vertexBufferMemory1; +VkBuffer vertexBuffer2; +VkDeviceMemory vertexBufferMemory2; +VkPhysicalDeviceMemoryProperties pdmp; +std::vector views; //? +VkSurfaceFormatKHR swapchainFormat; +VkExtent2D swapChainExtent; +VkPipelineLayout pipelineLayout; +VkImage depthImage; +VkImageView depthImageView; +VkDeviceMemory depthImageMemory; +VkFormat depthFormat; + +uint32_t graphicsQueueFamily; +uint32_t presentQueueFamily; + +void cleanup() { + vkDeviceWaitIdle(device); + + // Note: this is done implicitly when the command pool is freed, but nice to know about + vkFreeCommandBuffers(device, commandPool, presentCommandBuffers.size(), presentCommandBuffers.data()); + vkDestroyCommandPool(device, commandPool, nullptr); + + vkDestroySemaphore(device, imageAvailableSemaphore, nullptr); + vkDestroySemaphore(device, renderingFinishedSemaphore, nullptr); + + for(int c = 0; c < views.size(); ++c) + vkDestroyImageView(device, views[c], 0); + + for (int c = 0; c < fbs.size(); ++c) + vkDestroyFramebuffer(device, fbs[c], 0); + + vkDestroyRenderPass(device, renderPass, 0); + + vkDestroyShaderModule(device, shaderModule, 0); + + vkDestroyPipeline(device, pipeline, 0); + + // Note: implicitly destroys images (in fact, we're not allowed to do that explicitly) + vkDestroySwapchainKHR(device, swapChain, nullptr); + + vkDestroyDevice(device, nullptr); + + vkDestroySurfaceKHR(instance, windowSurface, nullptr); + + vkDestroyInstance(instance, nullptr); +} + +void run() { + // Note: dynamically loading loader may be a better idea to fail gracefully when Vulkan is not supported + + // Create window for Vulkan + //glfwInit(); + + //glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + //glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); + + //window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "The 630 line cornflower blue window", nullptr, nullptr); + + // Use Vulkan + setupVulkan(); + + mainLoop(); + + cleanup(); +} + +void setupVulkan() { + createInstance(); + findPhysicalDevice(); + createWindowSurface(); + checkSwapChainSupport(); + findQueueFamilies(); + createLogicalDevice(); + createSemaphores(); + createSwapChain(); + createCommandQueues(); + createDepthBuffer(); + CreateRenderPass(); + CreateFramebuffer(); + CreateVertexBuffer(); + //CreateUniformBuffer(); + CreateShaders(); + CreatePipeline(); + recordCommandBuffers(); +} + +void mainLoop() { + //while (!glfwWindowShouldClose(window)) { + for(int c = 0; c < 300; ++c){ + draw(); + + //glfwPollEvents(); + } +} + +void createInstance() { + VkApplicationInfo appInfo = {}; + appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + appInfo.pApplicationName = "VulkanTriangle"; + appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); + appInfo.pEngineName = "TriangleEngine"; + appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0); + appInfo.apiVersion = VK_API_VERSION_1_0; + + // Get instance extensions required by GLFW to draw to window + //unsigned int glfwExtensionCount; + //const char** glfwExtensions; + //glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount); + + // Check for extensions + uint32_t extensionCount = 0; + vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr); + + if (extensionCount == 0) { + std::cerr << "no extensions supported!" << std::endl; + assert(0); + } + + std::vector availableExtensions(extensionCount); + vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, availableExtensions.data()); + + std::cout << "supported extensions:" << std::endl; + + for (const auto& extension : availableExtensions) { + std::cout << "\t" << extension.extensionName << std::endl; + } + + const char* enabledExtensions[] = { + "VK_KHR_surface", + "VK_KHR_display" + }; + + VkInstanceCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + createInfo.pNext = 0; + createInfo.pApplicationInfo = &appInfo; + createInfo.enabledExtensionCount = sizeof(enabledExtensions) / sizeof(const char*); + createInfo.ppEnabledExtensionNames = enabledExtensions; + createInfo.enabledLayerCount = 0; + createInfo.ppEnabledLayerNames = 0; + + // Initialize Vulkan instance + if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) { + std::cerr << "failed to create instance!" << std::endl; + assert(0); + } + else { + std::cout << "created vulkan instance" << std::endl; + } +} + +void createWindowSurface() { + windowSurface = 0; + + uint32_t displayCount; + vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &displayCount, 0); + VkDisplayPropertiesKHR* displayProperties = (VkDisplayPropertiesKHR*)malloc(sizeof(VkDisplayPropertiesKHR)*displayCount); + vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &displayCount, displayProperties); + + printf("Enumerated displays\n"); + for(uint32_t c = 0; c < displayCount; ++c) + { + printf("Display ID %i\n", displayProperties[c].display); + printf("Display name %s\n", displayProperties[c].displayName); + printf("Display width %i\n", displayProperties[c].physicalDimensions.width); + printf("Display height %i\n", displayProperties[c].physicalDimensions.height); + printf("Display horizontal resolution %i\n", displayProperties[c].physicalResolution.width); + printf("Display vertical resolution %i\n", displayProperties[c].physicalResolution.height); + } + + uint32_t modeCount; + vkGetDisplayModePropertiesKHR(physicalDevice, displayProperties[0].display, &modeCount, 0); + VkDisplayModePropertiesKHR* displayModeProperties = (VkDisplayModePropertiesKHR*)malloc(sizeof(VkDisplayModePropertiesKHR)*modeCount); + vkGetDisplayModePropertiesKHR(physicalDevice, displayProperties[0].display, &modeCount, displayModeProperties); + +// printf("\nEnumerated modes\n"); +// for(uint32_t c = 0; c < modeCount; ++c) +// { +// printf("Mode refresh rate %i\n", displayModeProperties[c].parameters.refreshRate); +// printf("Mode width %i\n", displayModeProperties[c].parameters.visibleRegion.width); +// printf("Mode height %i\n\n", displayModeProperties[c].parameters.visibleRegion.height); +// } + + VkDisplaySurfaceCreateInfoKHR dsci = {}; + dsci.sType = VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR; + dsci.displayMode = displayModeProperties[0].displayMode; + dsci.transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + dsci.alphaMode = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR; + dsci.imageExtent = displayModeProperties[0].parameters.visibleRegion; + vkCreateDisplayPlaneSurfaceKHR(instance, &dsci, 0, &windowSurface); + + std::cout << "created window surface" << std::endl; +} + +void findPhysicalDevice() { + // Try to find 1 Vulkan supported device + // Note: perhaps refactor to loop through devices and find first one that supports all required features and extensions + uint32_t deviceCount = 1; + VkResult res = vkEnumeratePhysicalDevices(instance, &deviceCount, &physicalDevice); + if (res != VK_SUCCESS && res != VK_INCOMPLETE) { + std::cerr << "enumerating physical devices failed!" << std::endl; + assert(0); + } + + if (deviceCount == 0) { + std::cerr << "no physical devices that support vulkan!" << std::endl; + assert(0); + } + + std::cout << "physical device with vulkan support found" << std::endl; + + vkGetPhysicalDeviceMemoryProperties(physicalDevice, &pdmp); + + // Check device features + // Note: will apiVersion >= appInfo.apiVersion? Probably yes, but spec is unclear. + VkPhysicalDeviceProperties deviceProperties; + VkPhysicalDeviceFeatures deviceFeatures; + vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties); + vkGetPhysicalDeviceFeatures(physicalDevice, &deviceFeatures); + + uint32_t supportedVersion[] = { + VK_VERSION_MAJOR(deviceProperties.apiVersion), + VK_VERSION_MINOR(deviceProperties.apiVersion), + VK_VERSION_PATCH(deviceProperties.apiVersion) + }; + + std::cout << "physical device supports version " << supportedVersion[0] << "." << supportedVersion[1] << "." << supportedVersion[2] << std::endl; +} + +void checkSwapChainSupport() { + uint32_t extensionCount = 0; + vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionCount, nullptr); + + if (extensionCount == 0) { + std::cerr << "physical device doesn't support any extensions" << std::endl; + assert(0); + } + + std::vector deviceExtensions(extensionCount); + vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionCount, deviceExtensions.data()); + + for (const auto& extension : deviceExtensions) { + if (strcmp(extension.extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0) { + std::cout << "physical device supports swap chains" << std::endl; + return; + } + } + + std::cerr << "physical device doesn't support swap chains" << std::endl; + assert(0); +} + +void findQueueFamilies() { + // Check queue families + uint32_t queueFamilyCount = 0; + vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, nullptr); + + if (queueFamilyCount == 0) { + std::cout << "physical device has no queue families!" << std::endl; + assert(0); + } + + // Find queue family with graphics support + // Note: is a transfer queue necessary to copy vertices to the gpu or can a graphics queue handle that? + std::vector queueFamilies(queueFamilyCount); + vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, queueFamilies.data()); + + std::cout << "physical device has " << queueFamilyCount << " queue families" << std::endl; + + bool foundGraphicsQueueFamily = false; + bool foundPresentQueueFamily = false; + + for (uint32_t i = 0; i < queueFamilyCount; i++) { + VkBool32 presentSupport = false; + vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, i, windowSurface, &presentSupport); + + if (queueFamilies[i].queueCount > 0 && queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { + graphicsQueueFamily = i; + foundGraphicsQueueFamily = true; + + if (presentSupport) { + presentQueueFamily = i; + foundPresentQueueFamily = true; + break; + } + } + + if (!foundPresentQueueFamily && presentSupport) { + presentQueueFamily = i; + foundPresentQueueFamily = true; + } + } + + if (foundGraphicsQueueFamily) { + std::cout << "queue family #" << graphicsQueueFamily << " supports graphics" << std::endl; + + if (foundPresentQueueFamily) { + std::cout << "queue family #" << presentQueueFamily << " supports presentation" << std::endl; + } + else { + std::cerr << "could not find a valid queue family with present support" << std::endl; + assert(0); + } + } + else { + std::cerr << "could not find a valid queue family with graphics support" << std::endl; + assert(0); + } +} + +void createLogicalDevice() { + // Greate one graphics queue and optionally a separate presentation queue + float queuePriority = 1.0f; + + VkDeviceQueueCreateInfo queueCreateInfo[2] = {}; + + queueCreateInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfo[0].queueFamilyIndex = graphicsQueueFamily; + queueCreateInfo[0].queueCount = 1; + queueCreateInfo[0].pQueuePriorities = &queuePriority; + + queueCreateInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfo[0].queueFamilyIndex = presentQueueFamily; + queueCreateInfo[0].queueCount = 1; + queueCreateInfo[0].pQueuePriorities = &queuePriority; + + // Create logical device from physical device + // Note: there are separate instance and device extensions! + VkDeviceCreateInfo deviceCreateInfo = {}; + deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + deviceCreateInfo.pQueueCreateInfos = queueCreateInfo; + + if (graphicsQueueFamily == presentQueueFamily) { + deviceCreateInfo.queueCreateInfoCount = 1; + } + else { + deviceCreateInfo.queueCreateInfoCount = 2; + } + + const char* deviceExtensions = VK_KHR_SWAPCHAIN_EXTENSION_NAME; + deviceCreateInfo.enabledExtensionCount = 1; + deviceCreateInfo.ppEnabledExtensionNames = &deviceExtensions; + + if (vkCreateDevice(physicalDevice, &deviceCreateInfo, nullptr, &device) != VK_SUCCESS) { + std::cerr << "failed to create logical device" << std::endl; + assert(0); + } + + std::cout << "created logical device" << std::endl; + + // Get graphics and presentation queues (which may be the same) + vkGetDeviceQueue(device, graphicsQueueFamily, 0, &graphicsQueue); + vkGetDeviceQueue(device, presentQueueFamily, 0, &presentQueue); + + std::cout << "acquired graphics and presentation queues" << std::endl; +} + +void createSemaphores() { + VkSemaphoreCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + + if (vkCreateSemaphore(device, &createInfo, nullptr, &imageAvailableSemaphore) != VK_SUCCESS || + vkCreateSemaphore(device, &createInfo, nullptr, &renderingFinishedSemaphore) != VK_SUCCESS) { + std::cerr << "failed to create semaphores" << std::endl; + assert(0); + } + else { + std::cout << "created semaphores" << std::endl; + } +} + +void createSwapChain() { + // Find surface capabilities + VkSurfaceCapabilitiesKHR surfaceCapabilities; + if (vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, windowSurface, &surfaceCapabilities) != VK_SUCCESS) { + std::cerr << "failed to acquire presentation surface capabilities" << std::endl; + assert(0); + } + + // Find supported surface formats + uint32_t formatCount; + if (vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, windowSurface, &formatCount, nullptr) != VK_SUCCESS || formatCount == 0) { + std::cerr << "failed to get number of supported surface formats" << std::endl; + assert(0); + } + + std::vector surfaceFormats(formatCount); + if (vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, windowSurface, &formatCount, surfaceFormats.data()) != VK_SUCCESS) { + std::cerr << "failed to get supported surface formats" << std::endl; + assert(0); + } + + // Find supported present modes + uint32_t presentModeCount; + if (vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, windowSurface, &presentModeCount, nullptr) != VK_SUCCESS || presentModeCount == 0) { + std::cerr << "failed to get number of supported presentation modes" << std::endl; + assert(0); + } + + std::vector presentModes(presentModeCount); + if (vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, windowSurface, &presentModeCount, presentModes.data()) != VK_SUCCESS) { + std::cerr << "failed to get supported presentation modes" << std::endl; + assert(0); + } + + // Determine number of images for swap chain + uint32_t imageCount = surfaceCapabilities.minImageCount + 1; + if (surfaceCapabilities.maxImageCount != 0 && imageCount > surfaceCapabilities.maxImageCount) { + imageCount = surfaceCapabilities.maxImageCount; + } + + std::cout << "using " << imageCount << " images for swap chain" << std::endl; + + // Select a surface format + swapchainFormat = chooseSurfaceFormat(surfaceFormats); + + // Select swap chain size + swapChainExtent = chooseSwapExtent(surfaceCapabilities); + + // Check if swap chain supports being the destination of an image transfer + // Note: AMD driver bug, though it would be nice to implement a workaround that doesn't use transfering + //if (!(surfaceCapabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) { + // std::cerr << "swap chain image does not support VK_IMAGE_TRANSFER_DST usage" << std::endl; + //assert(0); + //} + + // Determine transformation to use (preferring no transform) + VkSurfaceTransformFlagBitsKHR surfaceTransform; + if (surfaceCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) { + surfaceTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + } + else { + surfaceTransform = surfaceCapabilities.currentTransform; + } + + // Choose presentation mode (preferring MAILBOX ~= triple buffering) + VkPresentModeKHR presentMode = choosePresentMode(presentModes); + + // Finally, create the swap chain + VkSwapchainCreateInfoKHR createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + createInfo.surface = windowSurface; + createInfo.minImageCount = imageCount; + createInfo.imageFormat = swapchainFormat.format; + createInfo.imageColorSpace = swapchainFormat.colorSpace; + createInfo.imageExtent = swapChainExtent; + createInfo.imageArrayLayers = 1; + createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + createInfo.queueFamilyIndexCount = 0; + createInfo.pQueueFamilyIndices = nullptr; + createInfo.preTransform = surfaceTransform; + createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + createInfo.presentMode = presentMode; + createInfo.clipped = VK_TRUE; + createInfo.oldSwapchain = VK_NULL_HANDLE; + + if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) { + std::cerr << "failed to create swap chain" << std::endl; + assert(0); + } + else { + std::cout << "created swap chain" << std::endl; + } + + // Store the images used by the swap chain + // Note: these are the images that swap chain image indices refer to + // Note: actual number of images may differ from requested number, since it's a lower bound + uint32_t actualImageCount = 0; + if (vkGetSwapchainImagesKHR(device, swapChain, &actualImageCount, nullptr) != VK_SUCCESS || actualImageCount == 0) { + std::cerr << "failed to acquire number of swap chain images" << std::endl; + assert(0); + } + + swapChainImages.resize(actualImageCount); + views.resize(actualImageCount); + + if (vkGetSwapchainImagesKHR(device, swapChain, &actualImageCount, swapChainImages.data()) != VK_SUCCESS) { + std::cerr << "failed to acquire swap chain images" << std::endl; + assert(0); + } + + std::cout << "acquired swap chain images" << std::endl; +} + +void createDepthBuffer() +{ + VkFormat depthFormats[] = + { //in order of preference + VK_FORMAT_D24_UNORM_S8_UINT, + VK_FORMAT_D16_UNORM_S8_UINT, + VK_FORMAT_D32_SFLOAT_S8_UINT, + VK_FORMAT_D32_SFLOAT, + VK_FORMAT_X8_D24_UNORM_PACK32, + VK_FORMAT_D16_UNORM, + }; + + uint32_t choice = -1; + for(uint32_t c = 0; c < sizeof(depthFormats) / sizeof(VkFormat); ++c) + { + VkFormatProperties props; + vkGetPhysicalDeviceFormatProperties(physicalDevice, depthFormats[c], &props); + if(props.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) + { + choice = c; + break; + } + } + + depthFormat = depthFormats[choice]; + + VkImageCreateInfo imageCreateInfo = {}; + imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; + imageCreateInfo.format = depthFormats[choice]; + imageCreateInfo.mipLevels = 1; + imageCreateInfo.arrayLayers = 1; + imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; + imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageCreateInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageCreateInfo.extent = { swapChainExtent.width, swapChainExtent.height, 1 }; + vkCreateImage(device, &imageCreateInfo, 0, &depthImage); + + VkMemoryRequirements mr; + vkGetImageMemoryRequirements(device, depthImage, &mr); + + VkMemoryAllocateInfo mai = {}; + mai.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + mai.allocationSize = mr.size; + mai.memoryTypeIndex = getMemoryTypeIndex(pdmp, mr.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + + vkAllocateMemory(device, &mai, 0, &depthImageMemory); + + vkBindImageMemory(device, depthImage, depthImageMemory, 0); + + VkImageViewCreateInfo view = {}; + view.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + view.viewType = VK_IMAGE_VIEW_TYPE_2D; + view.format = depthFormats[choice]; + view.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }; + view.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + view.subresourceRange.baseMipLevel = 0; + view.subresourceRange.baseArrayLayer = 0; + view.subresourceRange.layerCount = 1; + view.subresourceRange.levelCount = 1; + view.image = depthImage; + vkCreateImageView(device, &view, nullptr, &depthImageView); + + { //transition image + VkCommandBufferAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.commandPool = commandPool; + allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocInfo.commandBufferCount = 1; + + VkCommandBuffer transitionCommandBuffer; + + vkAllocateCommandBuffers(device, &allocInfo, &transitionCommandBuffer); + + VkImageMemoryBarrier imageMemoryBarrier = {}; + imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + imageMemoryBarrier.srcAccessMask = 0; + imageMemoryBarrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + imageMemoryBarrier.image = depthImageView; + imageMemoryBarrier.subresourceRange = view.subresourceRange; + + VkCommandBufferBeginInfo beginInfo = {}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; + + vkBeginCommandBuffer(transitionCommandBuffer, &beginInfo); + + vkCmdPipelineBarrier(transitionCommandBuffer, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, + 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); + + vkEndCommandBuffer(transitionCommandBuffer); + + VkFenceCreateInfo fenceInfo = {}; + fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fenceInfo.flags = 0; + + VkFence fence; + vkCreateFence(device, &fenceInfo, 0, &fence); + + VkSubmitInfo submitInfo = {}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &transitionCommandBuffer; + + vkQueueSubmit(graphicsQueue, 1, &submitInfo, fence); + + vkWaitForFences(device, 1, &fence, VK_TRUE, -1); + + vkDestroyFence(device, fence, 0); + vkFreeCommandBuffers(device, commandPool, 1, &transitionCommandBuffer); + } +} + +VkSurfaceFormatKHR chooseSurfaceFormat(const std::vector& availableFormats) { + // We can either choose any format + if (availableFormats.size() == 1 && availableFormats[0].format == VK_FORMAT_UNDEFINED) { + return { VK_FORMAT_R8G8B8A8_UNORM, VK_COLORSPACE_SRGB_NONLINEAR_KHR }; + } + + // Or go with the standard format - if available + for (const auto& availableSurfaceFormat : availableFormats) { + if (availableSurfaceFormat.format == VK_FORMAT_R8G8B8A8_UNORM) { + return availableSurfaceFormat; + } + } + + // Or fall back to the first available one + return availableFormats[0]; +} + +VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& surfaceCapabilities) { + if (surfaceCapabilities.currentExtent.width == -1) { + VkExtent2D swapChainExtent = {}; + +#define min(a, b) (a < b ? a : b) +#define max(a, b) (a > b ? a : b) + swapChainExtent.width = min(max(640, surfaceCapabilities.minImageExtent.width), surfaceCapabilities.maxImageExtent.width); + swapChainExtent.height = min(max(480, surfaceCapabilities.minImageExtent.height), surfaceCapabilities.maxImageExtent.height); + + return swapChainExtent; + } + else { + return surfaceCapabilities.currentExtent; + } +} + +VkPresentModeKHR choosePresentMode(const std::vector presentModes) { + for (const auto& presentMode : presentModes) { + if (presentMode == VK_PRESENT_MODE_MAILBOX_KHR) { + return presentMode; + } + } + + // If mailbox is unavailable, fall back to FIFO (guaranteed to be available) + return VK_PRESENT_MODE_FIFO_KHR; +} + +void createCommandQueues() { + // Create presentation command pool + // Note: only command buffers for a single queue family can be created from this pool + VkCommandPoolCreateInfo poolCreateInfo = {}; + poolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + poolCreateInfo.queueFamilyIndex = presentQueueFamily; + + if (vkCreateCommandPool(device, &poolCreateInfo, nullptr, &commandPool) != VK_SUCCESS) { + std::cerr << "failed to create command queue for presentation queue family" << std::endl; + assert(0); + } + else { + std::cout << "created command pool for presentation queue family" << std::endl; + } + + // Get number of swap chain images and create vector to hold command queue for each one + presentCommandBuffers.resize(swapChainImages.size()); + + // Allocate presentation command buffers + // Note: secondary command buffers are only for nesting in primary command buffers + VkCommandBufferAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.commandPool = commandPool; + allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocInfo.commandBufferCount = (uint32_t)swapChainImages.size(); + + if (vkAllocateCommandBuffers(device, &allocInfo, presentCommandBuffers.data()) != VK_SUCCESS) { + std::cerr << "failed to allocate presentation command buffers" << std::endl; + assert(0); + } + else { + std::cout << "allocated presentation command buffers" << std::endl; + } +} + +void recordCommandBuffers() +{ + // Prepare data for recording command buffers + VkCommandBufferBeginInfo beginInfo = {}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; + + // Note: contains value for each subresource range + VkClearValue clearValues[2] = {}; + clearValues[0].color = { 0.4f, 0.6f, 0.9f, 1.0f }; // R, G, B, A + clearValues[1].depthStencil = { 1.0f, 0xff }; + + VkImageSubresourceRange subResourceRange = {}; + subResourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + subResourceRange.baseMipLevel = 0; + subResourceRange.levelCount = 1; + subResourceRange.baseArrayLayer = 0; + subResourceRange.layerCount = 1; + + VkRenderPassBeginInfo renderPassInfo = {}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassInfo.renderPass = renderPass; + renderPassInfo.renderArea.offset.x = 0; + renderPassInfo.renderArea.offset.y = 0; + renderPassInfo.renderArea.extent.width = swapChainExtent.width; + renderPassInfo.renderArea.extent.height = swapChainExtent.height; + renderPassInfo.clearValueCount = 2; + renderPassInfo.pClearValues = clearValues; + + VkViewport viewport = { 0 }; + viewport.height = (float)swapChainExtent.width; + viewport.width = (float)swapChainExtent.height; + viewport.minDepth = (float)0.0f; + viewport.maxDepth = (float)1.0f; + + VkRect2D scissor = { 0 }; + scissor.extent.width = swapChainExtent.width; + scissor.extent.height = swapChainExtent.height; + scissor.offset.x = 0; + scissor.offset.y = 0; + + // Record the command buffer for every swap chain image + for (uint32_t i = 0; i < swapChainImages.size(); i++) { + // Record command buffer + vkBeginCommandBuffer(presentCommandBuffers[i], &beginInfo); + + renderPassInfo.framebuffer = fbs[i]; + + vkCmdBeginRenderPass(presentCommandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); + + vkCmdBindPipeline(presentCommandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + + float Wcoeff = 1.0f; //1.0f / Wc = 2.0 - Wcoeff + float viewportScaleX = (float)(swapChainExtent.width) * 0.5f * 16.0f; + float viewportScaleY = 1.0f * (float)(swapChainExtent.height) * 0.5f * 16.0f; + float Zs = 1.0f; + float Zo = 0.0f; + + uint32_t pushConstants[5]; + pushConstants[0] = *(uint32_t*)&Wcoeff; + pushConstants[1] = *(uint32_t*)&viewportScaleX; + pushConstants[2] = *(uint32_t*)&viewportScaleY; + pushConstants[3] = *(uint32_t*)&Zs; + pushConstants[4] = *(uint32_t*)&Zo; + + vkCmdPushConstants(presentCommandBuffers[i], pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(pushConstants), &pushConstants); + + //even thought yellow is rendered last, if depth buffering works we expect purple to be on top + + uint32_t fragColor = 0xffa14ccc; //purple + vkCmdPushConstants(presentCommandBuffers[i], pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(fragColor), &fragColor); + + VkDeviceSize offsets = 0; + vkCmdBindVertexBuffers(presentCommandBuffers[i], 0, 1, &vertexBuffer1, &offsets ); + vkCmdDraw(presentCommandBuffers[i], 3, 1, 0, 0); + + VkClearAttachment clearAttachment = {}; + clearAttachment.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + clearAttachment.clearValue.depthStencil.depth = 0.0f; + VkClearRect clearRect = {}; + clearRect.rect.offset.x = 0; + clearRect.rect.offset.y = 0; + clearRect.rect.extent.width = swapChainExtent.width; + clearRect.rect.extent.height = swapChainExtent.height; + vkCmdClearAttachments(presentCommandBuffers[i], 1, &clearAttachment, 1, &clearRect); + + fragColor = 0xffafcd02; //yellow + vkCmdPushConstants(presentCommandBuffers[i], pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(fragColor), &fragColor); + + vkCmdBindVertexBuffers(presentCommandBuffers[i], 0, 1, &vertexBuffer2, &offsets ); + vkCmdDraw(presentCommandBuffers[i], 3, 1, 0, 0); + + vkCmdEndRenderPass(presentCommandBuffers[i]); + + if (vkEndCommandBuffer(presentCommandBuffers[i]) != VK_SUCCESS) { + std::cerr << "failed to record command buffer" << std::endl; + assert(0); + } + else { + std::cout << "recorded command buffer for image " << i << std::endl; + } + } +} + +void draw() { + // Acquire image + uint32_t imageIndex; + VkResult res = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex); + + if (res != VK_SUCCESS && res != VK_SUBOPTIMAL_KHR) { + std::cerr << "failed to acquire image" << std::endl; + assert(0); + } + + std::cout << "acquired image" << std::endl; + + // Wait for image to be available and draw + VkSubmitInfo submitInfo = {}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + + submitInfo.waitSemaphoreCount = 1; + submitInfo.pWaitSemaphores = &imageAvailableSemaphore; + + submitInfo.signalSemaphoreCount = 1; + submitInfo.pSignalSemaphores = &renderingFinishedSemaphore; + + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &presentCommandBuffers[imageIndex]; + + if (vkQueueSubmit(presentQueue, 1, &submitInfo, VK_NULL_HANDLE) != VK_SUCCESS) { + std::cerr << "failed to submit draw command buffer" << std::endl; + assert(0); + } + + std::cout << "submitted draw command buffer" << std::endl; + + // Present drawn image + // Note: semaphore here is not strictly necessary, because commands are processed in submission order within a single queue + VkPresentInfoKHR presentInfo = {}; + presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + presentInfo.waitSemaphoreCount = 1; + presentInfo.pWaitSemaphores = &renderingFinishedSemaphore; + + presentInfo.swapchainCount = 1; + presentInfo.pSwapchains = &swapChain; + presentInfo.pImageIndices = &imageIndex; + + res = vkQueuePresentKHR(presentQueue, &presentInfo); + + if (res != VK_SUCCESS) { + std::cerr << "failed to submit present command buffer" << std::endl; + assert(0); + } + + std::cout << "submitted presentation command buffer" << std::endl; +} + +void CreateRenderPass() +{ + VkAttachmentReference attachRef = {}; + attachRef.attachment = 0; + attachRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkAttachmentReference depthAttachmentRef = {}; + depthAttachmentRef.attachment = 1; + depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + VkSubpassDescription subpassDesc = {}; + subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpassDesc.colorAttachmentCount = 1; + subpassDesc.pColorAttachments = &attachRef; + subpassDesc.pDepthStencilAttachment = &depthAttachmentRef; + + VkAttachmentDescription attachDesc[2]; + attachDesc[0] = {}; + attachDesc[0].format = swapchainFormat.format; // + attachDesc[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attachDesc[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachDesc[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachDesc[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachDesc[0].initialLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + attachDesc[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + attachDesc[0].samples = VK_SAMPLE_COUNT_1_BIT; + + attachDesc[1] = {}; + attachDesc[1].format = depthFormat; + attachDesc[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attachDesc[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachDesc[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attachDesc[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachDesc[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attachDesc[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + attachDesc[1].samples = VK_SAMPLE_COUNT_1_BIT; + + VkRenderPassCreateInfo renderPassCreateInfo = {}; + renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + renderPassCreateInfo.attachmentCount = 2; + renderPassCreateInfo.pAttachments = attachDesc; + renderPassCreateInfo.subpassCount = 1; + renderPassCreateInfo.pSubpasses = &subpassDesc; + + VkResult res = vkCreateRenderPass(device, &renderPassCreateInfo, NULL, &renderPass); + + printf("Created a render pass\n"); +} + + +void CreateFramebuffer() +{ + fbs.resize(swapChainImages.size()); + + VkResult res; + + for (uint32_t i = 0; i < swapChainImages.size(); i++) { + VkImageViewCreateInfo ViewCreateInfo = {}; + ViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + ViewCreateInfo.image = swapChainImages[i]; + ViewCreateInfo.format = swapchainFormat.format; // + ViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + ViewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; + ViewCreateInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; + ViewCreateInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; + ViewCreateInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; + ViewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + ViewCreateInfo.subresourceRange.baseMipLevel = 0; + ViewCreateInfo.subresourceRange.levelCount = 1; + ViewCreateInfo.subresourceRange.baseArrayLayer = 0; + ViewCreateInfo.subresourceRange.layerCount = 1; + + res = vkCreateImageView(device, &ViewCreateInfo, NULL, &views[i]); + + VkImageView attachments[] = + { + views[i], + depthImageView + }; + + VkFramebufferCreateInfo fbCreateInfo = {}; + fbCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + fbCreateInfo.renderPass = renderPass; + fbCreateInfo.attachmentCount = 2; + fbCreateInfo.pAttachments = attachments; + fbCreateInfo.width = swapChainExtent.width; + fbCreateInfo.height = swapChainExtent.height; + fbCreateInfo.layers = 1; + + res = vkCreateFramebuffer(device, &fbCreateInfo, NULL, &fbs[i]); + } + + printf("Frame buffers created\n"); +} + +void CreateShaders() +{ + char vs_asm_code[] = + ///0x40000000 = 2.0 + ///uni = 1.0 + ///rb0 = 2 - 1 = 1 + "sig_small_imm ; rx0 = fsub.ws.always(b, a, uni, 0x40000000) ; nop = nop(r0, r0) ;\n" + ///set up VPM read for subsequent reads + ///0x00201a00: 0000 0000 0010 0000 0001 1010 0000 0000 + ///addr: 0 + ///size: 32bit + ///packed + ///horizontal + ///stride=1 + ///vectors to read = 3 (how many components) + "sig_load_imm ; vr_setup = load32.always(0x00301a00) ; nop = load32.always() ;\n" + ///uni = viewportXScale + ///r0 = vpm * uni + "sig_none ; nop = nop(r0, r0, vpm_read, uni) ; r0 = fmul.always(a, b) ;\n" + ///r1 = r0 * rb0 (1) + "sig_none ; nop = nop(r0, r0, nop, rb0) ; r1 = fmul.always(r0, b) ;\n" + ///uni = viewportYScale + ///ra0.16a = int(r1), r2 = vpm * uni + "sig_none ; rx0.16a = ftoi.always(r1, r1, vpm_read, uni) ; r2 = fmul.always(a, b) ;\n" + ///r3 = r2 * rb0 + ///r0 = vpm + "sig_none ; r0 = or.always(a, a, vpm_read, rb0) ; r3 = fmul.always(r2, b) ;\n" + ///ra0.16b = int(r3) + ///r0 = r0 * 0.5 + "sig_none ; rx0.16b = ftoi.always(r3, r3, uni, nop) ; r0 = fmul.always(r0, a) ;\n" + ///set up VPM write for subsequent writes + ///0x00001a00: 0000 0000 0000 0000 0001 1010 0000 0000 + ///addr: 0 + ///size: 32bit + ///horizontal + ///stride = 1 + "sig_load_imm ; vw_setup = load32.always.ws(0x00001a00) ; nop = load32.always() ;\n" + ///shaded vertex format for PSE + /// Ys and Xs + ///vpm = ra0 + "sig_none ; vpm = or.always(a, a, ra0, nop) ; nop = nop(r0, r0);\n" + /// Zs + ///uni = 0.5 + ///vpm = uni + "sig_none ; vpm = fadd.always(r0, a, uni, nop) ; nop = nop(r0, r0);\n" + /// 1.0 / Wc + ///vpm = rb0 (1) + "sig_none ; vpm = or.always(b, b, nop, rb0) ; nop = nop(r0, r0);\n" + ///END + "sig_end ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;\n" + "sig_none ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;\n" + "sig_none ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;\n" + "\0"; + + char cs_asm_code[] = + ///uni = 1.0 + ///r3 = 2.0 - uni + "sig_small_imm ; r3 = fsub.always(b, a, uni, 0x40000000) ; nop = nop(r0, r0);\n" + "sig_load_imm ; vr_setup = load32.always(0x00301a00) ; nop = load32.always() ;\n" + ///r2 = vpm + "sig_none ; r2 = or.always(a, a, vpm_read, nop) ; nop = nop(r0, r0);\n" + "sig_load_imm ; vw_setup = load32.always.ws(0x00001a00) ; nop = load32.always() ;\n" + ///shaded coordinates format for PTB + /// write Xc + ///r1 = vpm, vpm = r2 + "sig_none ; r1 = or.always(a, a, vpm_read, nop) ; vpm = v8min.always(r2, r2);\n" + /// write Yc + ///uni = viewportXscale + ///vpm = r1, r2 = r2 * uni + "sig_none ; vpm = or.always(r1, r1, uni, nop) ; r2 = fmul.always(r2, a);\n" + ///uni = viewportYscale + ///r1 = r1 * uni + "sig_none ; nop = nop(r0, r0, uni, nop) ; r1 = fmul.always(r1, a);\n" + ///r0 = r2 * r3 + ///r2 = vpm + "sig_none ; r2 = or.always(a, a, vpm_read, nop) ; r0 = fmul.always(r2, r3);\n" + ///ra0.16a = r0, r1 = r1 * r3 + "sig_none ; rx0.16a = ftoi.always(r0, r0) ; r1 = fmul.always(r1, r3) ;\n" + ///ra0.16b = r1 + ///write Zc + "sig_none ; rx0.16b = ftoi.always(r1, r1) ; vpm = v8min.always(r2, r2) ;\n" + ///write Wc + ///vpm = 1.0 + ///r2 = r2 * uni (0.5) + "sig_small_imm ; vpm = or.always(b, b, uni, 0x3f800000) ; r2 = fmul.always(r2, a) ;\n" + ///write Ys and Xs + ///vpm = ra0 + "sig_none ; vpm = or.always(a, a, ra0, nop) ; nop = nop(r0, r0) ;\n" + ///write Zs + ///uni = 0.5 + ///vpm = r2 + "sig_none ; vpm = fadd.always(r2, a, uni, nop) ; nop = nop(r0, r0) ;\n" + ///write 1/Wc + ///vpm = r3 + "sig_none ; vpm = or.always(r3, r3) ; nop = nop(r0, r0) ;\n" + ///END + "sig_end ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;\n" + "sig_none ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;\n" + "sig_none ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;\n" + "\0"; + + //clever: use small immedate -1 interpreted as 0xffffffff (white) to set color to white + //"sig_small_imm ; tlb_color_all = or.always(b, b, nop, -1) ; nop = nop(r0, r0) ;" + + //8bit access + //abcd + //BGRA + + /** + //rainbow colors + char fs_asm_code[] = + "sig_none ; r1 = itof.always(a, a, x_pix, uni) ; r3 = v8min.always(b, b) ;" //can't use mul pipeline for conversion :( + "sig_load_imm ; r2 = load32.always(0x3a088888) ; nop = load32() ;" //1/1920 + "sig_none ; nop = nop(r0, r0) ; r2 = fmul.always(r2, r3);\n" + "sig_none ; r1 = itof.pm.always(b, b, x_pix, y_pix) ; r0.8c = fmul.always(r1, r2) ;" + "sig_load_imm ; r2 = load32.always(0x3a72b9d6) ; nop = load32() ;" //1/1080 + "sig_none ; nop = nop(r0, r0) ; r2 = fmul.always(r2, r3);\n" + "sig_none ; nop = nop.pm(r0, r0) ; r0.8b = fmul.always(r1, r2) ;" + "sig_small_imm ; nop = nop.pm(r0, r0, nop, 0) ; r0.8a = v8min.always(b, b) ;" + "sig_small_imm ; nop = nop.pm(r0, r0, nop, 1) ; r0.8d = v8min.always(b, b) ;" + "sig_none ; tlb_color_all = or.always(r0, r0) ; nop = nop(r0, r0) ;" + "sig_end ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;" + "sig_none ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;" + "sig_unlock_score ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;" + "\0"; + /**/ + + /**/ + //display a color + char fs_asm_code[] = + "sig_none ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;" + "sig_none ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;" + "sig_none ; tlb_z = or.always(b, b, nop, rb15) ; nop = nop(r0, r0) ;" + "sig_none ; tlb_color_all = or.always(a, a, uni, nop) ; nop = nop(r0, r0) ;" + "sig_end ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;" + "sig_none ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;" + "sig_unlock_score ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;" + "\0"; + /**/ + + char* asm_strings[] = + { + (char*)cs_asm_code, (char*)vs_asm_code, (char*)fs_asm_code, 0 + }; + + VkRpiAssemblyMappingEXT vertexMappings[] = { + //vertex shader uniforms + { + VK_RPI_ASSEMBLY_MAPPING_TYPE_PUSH_CONSTANT, + VK_DESCRIPTOR_TYPE_MAX_ENUM, //descriptor type + 0, //descriptor set # + 0, //descriptor binding # + 0, //descriptor array element # + 0, //resource offset + }, + { + VK_RPI_ASSEMBLY_MAPPING_TYPE_PUSH_CONSTANT, + VK_DESCRIPTOR_TYPE_MAX_ENUM, //descriptor type + 0, //descriptor set # + 0, //descriptor binding # + 0, //descriptor array element # + 4, //resource offset + }, + { + VK_RPI_ASSEMBLY_MAPPING_TYPE_PUSH_CONSTANT, + VK_DESCRIPTOR_TYPE_MAX_ENUM, //descriptor type + 0, //descriptor set # + 0, //descriptor binding # + 0, //descriptor array element # + 8, //resource offset + }, + { + VK_RPI_ASSEMBLY_MAPPING_TYPE_PUSH_CONSTANT, + VK_DESCRIPTOR_TYPE_MAX_ENUM, //descriptor type + 0, //descriptor set # + 0, //descriptor binding # + 0, //descriptor array element # + 12, //resource offset + }, + { + VK_RPI_ASSEMBLY_MAPPING_TYPE_PUSH_CONSTANT, + VK_DESCRIPTOR_TYPE_MAX_ENUM, //descriptor type + 0, //descriptor set # + 0, //descriptor binding # + 0, //descriptor array element # + 16, //resource offset + }, + }; + + VkRpiAssemblyMappingEXT fragmentMappings[] = { + { + VK_RPI_ASSEMBLY_MAPPING_TYPE_PUSH_CONSTANT, + VK_DESCRIPTOR_TYPE_MAX_ENUM, //descriptor type + 0, //descriptor set # + 0, //descriptor binding # + 0, //descriptor array element # + 0, //resource offset + } + }; + + uint32_t spirv[6]; + + uint64_t* asm_ptrs[4] = {}; + uint32_t asm_sizes[4] = {}; + + VkRpiAssemblyMappingEXT* asm_mappings[4] = {}; + uint32_t asm_mappings_sizes[4] = {}; + + VkRpiShaderModuleAssemblyCreateInfoEXT shaderModuleCreateInfo = {}; + shaderModuleCreateInfo.instructions = asm_ptrs; + shaderModuleCreateInfo.numInstructions = asm_sizes; + shaderModuleCreateInfo.mappings = asm_mappings; + shaderModuleCreateInfo.numMappings = asm_mappings_sizes; + + asm_mappings[VK_RPI_ASSEMBLY_TYPE_VERTEX] = vertexMappings; + asm_mappings_sizes[VK_RPI_ASSEMBLY_TYPE_VERTEX] = sizeof(vertexMappings) / sizeof(VkRpiAssemblyMappingEXT); + asm_mappings[VK_RPI_ASSEMBLY_TYPE_FRAGMENT] = fragmentMappings; + asm_mappings_sizes[VK_RPI_ASSEMBLY_TYPE_FRAGMENT] = sizeof(fragmentMappings) / sizeof(VkRpiAssemblyMappingEXT); + + { //assemble cs code + asm_sizes[0] = get_num_instructions(cs_asm_code); + uint32_t size = sizeof(uint64_t)*asm_sizes[0]; + asm_ptrs[0] = (uint64_t*)malloc(size); + assemble_qpu_asm(cs_asm_code, asm_ptrs[0]); + } + + { //assemble vs code + asm_sizes[1] = get_num_instructions(vs_asm_code); + uint32_t size = sizeof(uint64_t)*asm_sizes[1]; + asm_ptrs[1] = (uint64_t*)malloc(size); + assemble_qpu_asm(vs_asm_code, asm_ptrs[1]); + } + + { //assemble fs code + asm_sizes[2] = get_num_instructions(fs_asm_code); + uint32_t size = sizeof(uint64_t)*asm_sizes[2]; + asm_ptrs[2] = (uint64_t*)malloc(size); + assemble_qpu_asm(fs_asm_code, asm_ptrs[2]); + } + + spirv[0] = 0x07230203; + spirv[1] = 0x00010000; + spirv[2] = 0x14E45250; + spirv[3] = 1; + spirv[4] = (uint32_t)&shaderModuleCreateInfo; + //words start here + spirv[5] = 1 << 16; + + VkShaderModuleCreateInfo smci = {}; + smci.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + smci.codeSize = sizeof(uint32_t)*6; + smci.pCode = spirv; + vkCreateShaderModule(device, &smci, 0, &shaderModule); + + for(uint32_t c = 0; c < 4; ++c) + { + free(asm_ptrs[c]); + } +} + + +#define VERTEX_BUFFER_BIND_ID 0 + +void CreatePipeline() +{ + VkPushConstantRange pushConstantRanges[2]; + pushConstantRanges[0].offset = 0; + pushConstantRanges[0].size = 5 * 4; //5 * 32bits + pushConstantRanges[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + + pushConstantRanges[1].offset = 0; + pushConstantRanges[1].size = 1 * 4; //1 * 32bits + pushConstantRanges[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + + VkPipelineLayoutCreateInfo pipelineLayoutCI = {}; + pipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutCI.setLayoutCount = 0; + pipelineLayoutCI.pushConstantRangeCount = 2; + pipelineLayoutCI.pPushConstantRanges = &pushConstantRanges[0]; + vkCreatePipelineLayout(device, &pipelineLayoutCI, 0, &pipelineLayout); + + + VkPipelineShaderStageCreateInfo shaderStageCreateInfo[2] = {}; + + shaderStageCreateInfo[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shaderStageCreateInfo[0].stage = VK_SHADER_STAGE_VERTEX_BIT; + shaderStageCreateInfo[0].module = shaderModule; + shaderStageCreateInfo[0].pName = "main"; + shaderStageCreateInfo[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shaderStageCreateInfo[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; + shaderStageCreateInfo[1].module = shaderModule; + shaderStageCreateInfo[1].pName = "main"; + + VkVertexInputBindingDescription vertexInputBindingDescription = + { + 0, + sizeof(float) * 3, + VK_VERTEX_INPUT_RATE_VERTEX + }; + + VkVertexInputAttributeDescription vertexInputAttributeDescription = + { + 0, + 0, + VK_FORMAT_R32G32B32_SFLOAT, + 0 + }; + + VkPipelineVertexInputStateCreateInfo vertexInputInfo = {}; + vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertexInputInfo.vertexAttributeDescriptionCount = 1; + vertexInputInfo.pVertexAttributeDescriptions = &vertexInputAttributeDescription; + vertexInputInfo.vertexBindingDescriptionCount = 1; + vertexInputInfo.pVertexBindingDescriptions = &vertexInputBindingDescription; + + VkPipelineInputAssemblyStateCreateInfo pipelineIACreateInfo = {}; + pipelineIACreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + pipelineIACreateInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + + VkViewport vp = {}; + vp.x = 0.0f; + vp.y = 0.0f; + vp.width = (float)swapChainExtent.width; + vp.height = (float)swapChainExtent.height; + vp.minDepth = 0.0f; + vp.maxDepth = 1.0f; + + VkPipelineViewportStateCreateInfo vpCreateInfo = {}; + vpCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + vpCreateInfo.viewportCount = 1; + vpCreateInfo.pViewports = &vp; + + VkPipelineRasterizationStateCreateInfo rastCreateInfo = {}; + rastCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rastCreateInfo.polygonMode = VK_POLYGON_MODE_FILL; + rastCreateInfo.cullMode = VK_CULL_MODE_NONE; + rastCreateInfo.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rastCreateInfo.lineWidth = 1.0f; + + VkPipelineMultisampleStateCreateInfo pipelineMSCreateInfo = {}; + pipelineMSCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + + VkPipelineColorBlendAttachmentState blendAttachState = {}; + blendAttachState.colorWriteMask = 0xf; + blendAttachState.blendEnable = false; + + VkPipelineColorBlendStateCreateInfo blendCreateInfo = {}; + blendCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + blendCreateInfo.attachmentCount = 1; + blendCreateInfo.pAttachments = &blendAttachState; + + VkPipelineDepthStencilStateCreateInfo depthStencilState = {}; + depthStencilState.depthTestEnable = true; + depthStencilState.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; + depthStencilState.depthWriteEnable = true; + depthStencilState.stencilTestEnable = false; + + VkGraphicsPipelineCreateInfo pipelineInfo = {}; + pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipelineInfo.stageCount = 2; + pipelineInfo.pStages = &shaderStageCreateInfo[0]; + pipelineInfo.pVertexInputState = &vertexInputInfo; + pipelineInfo.pInputAssemblyState = &pipelineIACreateInfo; + pipelineInfo.pViewportState = &vpCreateInfo; + pipelineInfo.pRasterizationState = &rastCreateInfo; + pipelineInfo.pMultisampleState = &pipelineMSCreateInfo; + pipelineInfo.pColorBlendState = &blendCreateInfo; + pipelineInfo.renderPass = renderPass; + pipelineInfo.basePipelineIndex = -1; + pipelineInfo.pDepthStencilState = &depthStencilState; + pipelineInfo.layout = pipelineLayout; + + VkResult res = vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, NULL, &pipeline); + + printf("Graphics pipeline created\n"); +} + +uint32_t getMemoryTypeIndex(VkPhysicalDeviceMemoryProperties deviceMemoryProperties, uint32_t typeBits, VkMemoryPropertyFlags properties) +{ + // Iterate over all memory types available for the device used in this example + for (uint32_t i = 0; i < deviceMemoryProperties.memoryTypeCount; i++) + { + if ((typeBits & 1) == 1) + { + if ((deviceMemoryProperties.memoryTypes[i].propertyFlags & properties) == properties) + { + return i; + } + } + typeBits >>= 1; + } + + assert(0); +} + +void CreateVertexBuffer() +{ + unsigned vboSize = sizeof(float) * 3 * 3; //3 x vec3 + + VkBufferCreateInfo ci = {}; + ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + ci.size = vboSize; + ci.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + + VkMemoryRequirements mr; + + { //create staging buffer + VkResult res = vkCreateBuffer(device, &ci, 0, &vertexBuffer1); + + vkGetBufferMemoryRequirements(device, vertexBuffer1, &mr); + + VkMemoryAllocateInfo mai = {}; + mai.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + mai.allocationSize = mr.size; + mai.memoryTypeIndex = getMemoryTypeIndex(pdmp, mr.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + + res = vkAllocateMemory(device, &mai, 0, &vertexBufferMemory1); + + float vertices[] = + { + -1, 1, 0.2, + 1, 1, 0.2, + 0, -1, 0.2 + }; + + void* data; + res = vkMapMemory(device, vertexBufferMemory1, 0, mr.size, 0, &data); + memcpy(data, vertices, vboSize); + vkUnmapMemory(device, vertexBufferMemory1); + + res = vkBindBufferMemory(device, vertexBuffer1, vertexBufferMemory1, 0); + } + + { //create staging buffer + VkResult res = vkCreateBuffer(device, &ci, 0, &vertexBuffer2); + + vkGetBufferMemoryRequirements(device, vertexBuffer2, &mr); + + VkMemoryAllocateInfo mai = {}; + mai.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + mai.allocationSize = mr.size; + mai.memoryTypeIndex = getMemoryTypeIndex(pdmp, mr.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + + res = vkAllocateMemory(device, &mai, 0, &vertexBufferMemory2); + + float vertices[] = + { + -0.5, 1, 0.5, + 1.5, 1, 0.5, + 0.5, -1, 0.5 + }; + + void* data; + res = vkMapMemory(device, vertexBufferMemory2, 0, mr.size, 0, &data); + memcpy(data, vertices, vboSize); + vkUnmapMemory(device, vertexBufferMemory2); + + res = vkBindBufferMemory(device, vertexBuffer2, vertexBufferMemory2, 0); + } + + printf("Vertex buffer created\n"); +} + +int main() { + // Note: dynamically loading loader may be a better idea to fail gracefully when Vulkan is not supported + + // Create window for Vulkan + //glfwInit(); + + //glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + //glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); + + //window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "The 630 line cornflower blue window", nullptr, nullptr); + + // Use Vulkan + setupVulkan(); + + mainLoop(); + + cleanup(); + + + return 0; +}