void SparseShaderIntrinsicsInstanceSampledBase::recordCommands (const VkCommandBuffer commandBuffer, const VkImageCreateInfo& imageSparseInfo, const VkImage imageSparse, const VkImage imageTexels, const VkImage imageResidency) { const InstanceInterface& instance = m_context.getInstanceInterface(); const DeviceInterface& deviceInterface = getDeviceInterface(); const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice(); const VkPhysicalDeviceProperties deviceProperties = getPhysicalDeviceProperties(instance, physicalDevice); if (imageSparseInfo.extent.width > deviceProperties.limits.maxFramebufferWidth || imageSparseInfo.extent.height > deviceProperties.limits.maxFramebufferHeight || imageSparseInfo.arrayLayers > deviceProperties.limits.maxFramebufferLayers) { TCU_THROW(NotSupportedError, "Image size exceeds allowed framebuffer dimensions"); } // Check if device supports image format for sampled images if (!checkImageFormatFeatureSupport(instance, physicalDevice, imageSparseInfo.format, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) TCU_THROW(NotSupportedError, "Device does not support image format for sampled images"); // Check if device supports image format for color attachment if (!checkImageFormatFeatureSupport(instance, physicalDevice, imageSparseInfo.format, VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) TCU_THROW(NotSupportedError, "Device does not support image format for color attachment"); // Make sure device supports VK_FORMAT_R32_UINT format for color attachment if (!checkImageFormatFeatureSupport(instance, physicalDevice, mapTextureFormat(m_residencyFormat), VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) TCU_THROW(TestError, "Device does not support VK_FORMAT_R32_UINT format for color attachment"); // Create buffer storing vertex data std::vector<tcu::Vec2> vertexData; vertexData.push_back(tcu::Vec2(-1.0f,-1.0f)); vertexData.push_back(tcu::Vec2( 0.0f, 0.0f)); vertexData.push_back(tcu::Vec2(-1.0f, 1.0f)); vertexData.push_back(tcu::Vec2( 0.0f, 1.0f)); vertexData.push_back(tcu::Vec2( 1.0f,-1.0f)); vertexData.push_back(tcu::Vec2( 1.0f, 0.0f)); vertexData.push_back(tcu::Vec2( 1.0f, 1.0f)); vertexData.push_back(tcu::Vec2( 1.0f, 1.0f)); const VkDeviceSize vertexDataSizeInBytes = sizeInBytes(vertexData); const VkBufferCreateInfo vertexBufferCreateInfo = makeBufferCreateInfo(vertexDataSizeInBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); m_vertexBuffer = createBuffer(deviceInterface, getDevice(), &vertexBufferCreateInfo); m_vertexBufferAlloc = bindBuffer(deviceInterface, getDevice(), getAllocator(), *m_vertexBuffer, MemoryRequirement::HostVisible); deMemcpy(m_vertexBufferAlloc->getHostPtr(), &vertexData[0], static_cast<std::size_t>(vertexDataSizeInBytes)); flushMappedMemoryRange(deviceInterface, getDevice(), m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset(), vertexDataSizeInBytes); // Create render pass const VkAttachmentDescription texelsAttachmentDescription = { (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags; imageSparseInfo.format, // VkFormat format; VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp; VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp; VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp; VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp; VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout initialLayout; VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout; }; const VkAttachmentDescription residencyAttachmentDescription = { (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags; mapTextureFormat(m_residencyFormat), // VkFormat format; VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp; VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp; VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp; VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp; VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout initialLayout; VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout; }; const VkAttachmentDescription colorAttachmentsDescription[] = { texelsAttachmentDescription, residencyAttachmentDescription }; const VkAttachmentReference texelsAttachmentReference = { 0u, // deUint32 attachment; VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout; }; const VkAttachmentReference residencyAttachmentReference = { 1u, // deUint32 attachment; VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout; }; const VkAttachmentReference colorAttachmentsReference[] = { texelsAttachmentReference, residencyAttachmentReference }; const VkAttachmentReference depthAttachmentReference = { VK_ATTACHMENT_UNUSED, // deUint32 attachment; VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout layout; }; const VkSubpassDescription subpassDescription = { (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags; VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint; 0u, // deUint32 inputAttachmentCount; DE_NULL, // const VkAttachmentReference* pInputAttachments; 2u, // deUint32 colorAttachmentCount; colorAttachmentsReference, // const VkAttachmentReference* pColorAttachments; DE_NULL, // const VkAttachmentReference* pResolveAttachments; &depthAttachmentReference, // const VkAttachmentReference* pDepthStencilAttachment; 0u, // deUint32 preserveAttachmentCount; DE_NULL // const deUint32* pPreserveAttachments; }; const VkRenderPassCreateInfo renderPassInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags; 2u, // deUint32 attachmentCount; colorAttachmentsDescription, // const VkAttachmentDescription* pAttachments; 1u, // deUint32 subpassCount; &subpassDescription, // const VkSubpassDescription* pSubpasses; 0u, // deUint32 dependencyCount; DE_NULL // const VkSubpassDependency* pDependencies; }; m_renderPass = createRenderPass(deviceInterface, getDevice(), &renderPassInfo); // Create descriptor set layout DescriptorSetLayoutBuilder descriptorLayerBuilder; descriptorLayerBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT); const Unique<VkDescriptorSetLayout> descriptorSetLayout(descriptorLayerBuilder.build(deviceInterface, getDevice())); // Create descriptor pool DescriptorPoolBuilder descriptorPoolBuilder; descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, imageSparseInfo.mipLevels); descriptorPool = descriptorPoolBuilder.build(deviceInterface, getDevice(), VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, imageSparseInfo.mipLevels); // Create sampler object const tcu::Sampler samplerObject(tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, tcu::Sampler::NEAREST_MIPMAP_NEAREST, tcu::Sampler::NEAREST); const VkSamplerCreateInfo samplerCreateInfo = mapSampler(samplerObject, m_format); m_sampler = createSampler(deviceInterface, getDevice(), &samplerCreateInfo); struct PushConstants { deUint32 lod; deUint32 padding; // padding needed to satisfy std430 rules float lodWidth; float lodHeight; }; // Create pipeline layout const VkPushConstantRange lodConstantRange = { VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlags stageFlags; 0u, // deUint32 offset; sizeof(PushConstants), // deUint32 size; }; const VkPipelineLayoutCreateInfo pipelineLayoutParams = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineLayoutCreateFlags flags; 1u, // deUint32 setLayoutCount; &descriptorSetLayout.get(), // const VkDescriptorSetLayout* pSetLayouts; 1u, // deUint32 pushConstantRangeCount; &lodConstantRange, // const VkPushConstantRange* pPushConstantRanges; }; const Unique<VkPipelineLayout> pipelineLayout(createPipelineLayout(deviceInterface, getDevice(), &pipelineLayoutParams)); // Create graphics pipeline { Move<VkShaderModule> vertexModule = createShaderModule(deviceInterface, getDevice(), m_context.getBinaryCollection().get("vertex_shader"), (VkShaderModuleCreateFlags)0); Move<VkShaderModule> fragmentModule = createShaderModule(deviceInterface, getDevice(), m_context.getBinaryCollection().get("fragment_shader"), (VkShaderModuleCreateFlags)0); Move<VkShaderModule> geometryModule; if (imageSparseInfo.arrayLayers > 1u) { requireFeatures(instance, physicalDevice, FEATURE_GEOMETRY_SHADER); geometryModule = createShaderModule(deviceInterface, getDevice(), m_context.getBinaryCollection().get("geometry_shader"), (VkShaderModuleCreateFlags)0); } pipelines.push_back(makeVkSharedPtr(makeGraphicsPipeline( deviceInterface, getDevice(), *pipelineLayout, *m_renderPass, *vertexModule, *fragmentModule, *geometryModule))); } const VkPipeline graphicsPipeline = **pipelines[0]; { const VkImageSubresourceRange fullImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, imageSparseInfo.mipLevels, 0u, imageSparseInfo.arrayLayers); VkImageMemoryBarrier imageShaderAccessBarriers[3]; imageShaderAccessBarriers[0] = makeImageMemoryBarrier ( VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, imageSparse, fullImageSubresourceRange ); imageShaderAccessBarriers[1] = makeImageMemoryBarrier ( 0u, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, imageTexels, fullImageSubresourceRange ); imageShaderAccessBarriers[2] = makeImageMemoryBarrier ( 0u, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, imageResidency, fullImageSubresourceRange ); deviceInterface.cmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 3u, imageShaderAccessBarriers); } imageSparseViews.resize(imageSparseInfo.mipLevels); imageTexelsViews.resize(imageSparseInfo.mipLevels); imageResidencyViews.resize(imageSparseInfo.mipLevels); m_framebuffers.resize(imageSparseInfo.mipLevels); descriptorSets.resize(imageSparseInfo.mipLevels); std::vector<VkClearValue> clearValues; clearValues.push_back(makeClearValueColor(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f))); clearValues.push_back(makeClearValueColor(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f))); for (deUint32 mipLevelNdx = 0u; mipLevelNdx < imageSparseInfo.mipLevels; ++mipLevelNdx) { const vk::VkExtent3D mipLevelSize = mipLevelExtents(imageSparseInfo.extent, mipLevelNdx); const vk::VkRect2D renderArea = makeRect2D(mipLevelSize); const VkViewport viewport = makeViewport(mipLevelSize); const VkImageSubresourceRange mipLevelRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, mipLevelNdx, 1u, 0u, imageSparseInfo.arrayLayers); // Create color attachments image views imageTexelsViews[mipLevelNdx] = makeVkSharedPtr(makeImageView(deviceInterface, getDevice(), imageTexels, mapImageViewType(m_imageType), imageSparseInfo.format, mipLevelRange)); imageResidencyViews[mipLevelNdx] = makeVkSharedPtr(makeImageView(deviceInterface, getDevice(), imageResidency, mapImageViewType(m_imageType), mapTextureFormat(m_residencyFormat), mipLevelRange)); const VkImageView attachmentsViews[] = { **imageTexelsViews[mipLevelNdx], **imageResidencyViews[mipLevelNdx] }; // Create framebuffer const VkFramebufferCreateInfo framebufferInfo = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; (VkFramebufferCreateFlags)0, // VkFramebufferCreateFlags flags; *m_renderPass, // VkRenderPass renderPass; 2u, // uint32_t attachmentCount; attachmentsViews, // const VkImageView* pAttachments; mipLevelSize.width, // uint32_t width; mipLevelSize.height, // uint32_t height; imageSparseInfo.arrayLayers, // uint32_t layers; }; m_framebuffers[mipLevelNdx] = makeVkSharedPtr(createFramebuffer(deviceInterface, getDevice(), &framebufferInfo)); // Create descriptor set descriptorSets[mipLevelNdx] = makeVkSharedPtr(makeDescriptorSet(deviceInterface, getDevice(), *descriptorPool, *descriptorSetLayout)); const VkDescriptorSet descriptorSet = **descriptorSets[mipLevelNdx]; // Update descriptor set const VkImageSubresourceRange sparseImageSubresourceRange = sampledImageRangeToBind(imageSparseInfo, mipLevelNdx); imageSparseViews[mipLevelNdx] = makeVkSharedPtr(makeImageView(deviceInterface, getDevice(), imageSparse, mapImageViewType(m_imageType), imageSparseInfo.format, sparseImageSubresourceRange)); const VkDescriptorImageInfo imageSparseDescInfo = makeDescriptorImageInfo(*m_sampler, **imageSparseViews[mipLevelNdx], VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); DescriptorSetUpdateBuilder descriptorUpdateBuilder; descriptorUpdateBuilder.writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(BINDING_IMAGE_SPARSE), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageSparseDescInfo); descriptorUpdateBuilder.update(deviceInterface, getDevice()); // Begin render pass beginRenderPass(deviceInterface, commandBuffer, *m_renderPass, **m_framebuffers[mipLevelNdx], renderArea, (deUint32)clearValues.size(), &clearValues[0]); // Bind graphics pipeline deviceInterface.cmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline); // Bind descriptor set deviceInterface.cmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet, 0u, DE_NULL); // Bind vertex buffer { const VkDeviceSize offset = 0ull; deviceInterface.cmdBindVertexBuffers(commandBuffer, 0u, 1u, &m_vertexBuffer.get(), &offset); } // Bind Viewport deviceInterface.cmdSetViewport(commandBuffer, 0u, 1u, &viewport); // Bind Scissor Rectangle deviceInterface.cmdSetScissor(commandBuffer, 0u, 1u, &renderArea); const PushConstants pushConstants = { mipLevelNdx, 0u, // padding static_cast<float>(mipLevelSize.width), static_cast<float>(mipLevelSize.height) }; // Update push constants deviceInterface.cmdPushConstants(commandBuffer, *pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0u, sizeof(PushConstants), &pushConstants); // Draw full screen quad deviceInterface.cmdDraw(commandBuffer, 4u, 1u, 0u, 0u); // End render pass endRenderPass(deviceInterface, commandBuffer); } { const VkImageSubresourceRange fullImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, imageSparseInfo.mipLevels, 0u, imageSparseInfo.arrayLayers); VkImageMemoryBarrier imageOutputTransferSrcBarriers[2]; imageOutputTransferSrcBarriers[0] = makeImageMemoryBarrier ( VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, imageTexels, fullImageSubresourceRange ); imageOutputTransferSrcBarriers[1] = makeImageMemoryBarrier ( VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, imageResidency, fullImageSubresourceRange ); deviceInterface.cmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 2u, imageOutputTransferSrcBarriers); } }
agpu_framebuffer *_agpu_framebuffer::create(agpu_device *device, agpu_uint width, agpu_uint height, agpu_uint colorCount, agpu_texture_view_description* colorViews, agpu_texture_view_description* depthStencilView) { agpu_framebuffer *result = nullptr; // Attachments std::vector<VkAttachmentDescription> attachments(colorCount + (depthStencilView != nullptr ? 1 : 0)); for (agpu_uint i = 0; i < colorCount; ++i) { auto view = &colorViews[i]; auto &attachment = attachments[i]; if (!view || !view->texture) return nullptr; attachment.format = mapTextureFormat(view->format); attachment.samples = VK_SAMPLE_COUNT_1_BIT; attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; attachment.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; attachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; } if (depthStencilView != nullptr) { if (!depthStencilView->texture) return nullptr; auto &attachment = attachments.back(); attachment.format = mapTextureFormat(depthStencilView->format); attachment.samples = VK_SAMPLE_COUNT_1_BIT; attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; attachment.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; attachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; } // Color reference std::vector<VkAttachmentReference> colorReference(colorCount); for (agpu_uint i = 0; i < colorCount; ++i) { colorReference[i].attachment = i; colorReference[i].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; } // Depth reference VkAttachmentReference depthReference; memset(&depthReference, 0, sizeof(depthReference)); depthReference.attachment = colorCount; depthReference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; // Sub pass VkSubpassDescription subpass; memset(&subpass, 0, sizeof(subpass)); subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subpass.colorAttachmentCount = colorCount; subpass.pColorAttachments = &colorReference[0]; subpass.pDepthStencilAttachment = &depthReference; if (!depthStencilView) subpass.pDepthStencilAttachment = nullptr; // Render pass VkRenderPassCreateInfo renderPassCreateInfo; memset(&renderPassCreateInfo, 0, sizeof(renderPassCreateInfo)); renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; renderPassCreateInfo.attachmentCount = attachments.size(); renderPassCreateInfo.pAttachments = &attachments[0]; renderPassCreateInfo.subpassCount = 1; renderPassCreateInfo.pSubpasses = &subpass; VkRenderPass renderPass; auto error = vkCreateRenderPass(device->device, &renderPassCreateInfo, nullptr, &renderPass); if (error) return nullptr; // Create the framebuffer std::vector<VkImageView> attachmentViews(attachments.size()); for (agpu_uint i = 0; i < colorCount; ++i) { auto view = agpu_texture::createImageView(device, &colorViews[i]); if (!view) goto failure; attachmentViews[i] = view; } if (depthStencilView) { auto view = agpu_texture::createImageView(device, depthStencilView); if (!view) goto failure; attachmentViews.back() = view; } VkFramebufferCreateInfo createInfo; memset(&createInfo, 0, sizeof(createInfo)); createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; createInfo.attachmentCount = attachmentViews.size(); createInfo.pAttachments = &attachmentViews[0]; createInfo.renderPass = renderPass; createInfo.width = width; createInfo.height = height; createInfo.layers = 1; VkFramebuffer framebuffer; error = vkCreateFramebuffer(device->device, &createInfo, nullptr, &framebuffer); if (error) goto failure; result = new agpu_framebuffer(device); result->colorCount = colorCount; result->hasDepthStencil = depthStencilView != nullptr; result->width = width; result->height = height; result->renderPass = renderPass; result->framebuffer = framebuffer; result->attachmentViews = attachmentViews; result->attachmentTextures.resize(attachmentViews.size()); for (agpu_uint i = 0; i < colorCount; ++i) { auto texture = colorViews[i].texture; texture->retain(); result->attachmentTextures[i] = texture; } if (depthStencilView) { auto texture = depthStencilView->texture; texture->retain(); result->attachmentTextures.back() = texture; } return result; failure: vkDestroyRenderPass(device->device, renderPass, nullptr); for (auto view : attachmentViews) { if (view) vkDestroyImageView(device->device, view, nullptr); } return nullptr; }
_agpu_swap_chain *_agpu_swap_chain::create(agpu_device *device, agpu_command_queue* graphicsCommandQueue, agpu_swap_chain_create_info *createInfo) { VkSurfaceKHR surface = VK_NULL_HANDLE; if (!graphicsCommandQueue || !createInfo) return nullptr; #if defined(_WIN32) if (!createInfo->window) return nullptr; VkWin32SurfaceCreateInfoKHR surfaceCreateInfo; memset(&surfaceCreateInfo, 0, sizeof(surfaceCreateInfo)); surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; surfaceCreateInfo.hinstance = GetModuleHandle(nullptr); surfaceCreateInfo.hwnd = (HWND)createInfo->window; auto error = vkCreateWin32SurfaceKHR(device->vulkanInstance, &surfaceCreateInfo, nullptr, &surface); #elif defined(__unix__) if(!device->displayHandle) device->displayHandle = XOpenDisplay(nullptr); if (!createInfo->window) return nullptr; VkXcbSurfaceCreateInfoKHR surfaceCreateInfo; memset(&surfaceCreateInfo, 0, sizeof(surfaceCreateInfo)); surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; surfaceCreateInfo.connection = XGetXCBConnection((Display*)device->displayHandle); surfaceCreateInfo.window = (xcb_window_t)(uintptr_t)createInfo->window; auto error = vkCreateXcbSurfaceKHR(device->vulkanInstance, &surfaceCreateInfo, nullptr, &surface); #else #error unsupported platform #endif if (error) { printError("Failed to create the swap chain surface\n"); return nullptr; } agpu_command_queue *presentationQueue = graphicsCommandQueue; if (!graphicsCommandQueue->supportsPresentingSurface(surface)) { // TODO: Find a presentation queue. vkDestroySurfaceKHR(device->vulkanInstance, surface, nullptr); printError("Surface presentation in different queue is not yet supported.\n"); return nullptr; } uint32_t formatCount = 0; error = device->fpGetPhysicalDeviceSurfaceFormatsKHR(device->physicalDevice, surface, &formatCount, nullptr); if (error) { vkDestroySurfaceKHR(device->vulkanInstance, surface, nullptr); return nullptr; } std::vector<VkSurfaceFormatKHR> surfaceFormats(formatCount); error = device->fpGetPhysicalDeviceSurfaceFormatsKHR(device->physicalDevice, surface, &formatCount, &surfaceFormats[0]); if (error) { vkDestroySurfaceKHR(device->vulkanInstance, surface, nullptr); return nullptr; } // Create the swap chain object. auto swapChain = new agpu_swap_chain(device); swapChain->surface = surface; swapChain->graphicsQueue = graphicsCommandQueue; swapChain->presentationQueue = presentationQueue; graphicsCommandQueue->retain(); presentationQueue->retain(); // Set the format. agpu_texture_format actualFormat = createInfo->colorbuffer_format; if (formatCount == 1 && surfaceFormats[0].format == VK_FORMAT_UNDEFINED) { swapChain->format = mapTextureFormat(createInfo->colorbuffer_format); if (swapChain->format == VK_FORMAT_UNDEFINED) { swapChain->format = VK_FORMAT_B8G8R8A8_UNORM; actualFormat = AGPU_TEXTURE_FORMAT_B8G8R8A8_UNORM; } swapChain->colorSpace = surfaceFormats[0].colorSpace; } else { assert(formatCount >= 1); // Start selecting the first format. swapChain->format = surfaceFormats[0].format; swapChain->colorSpace = surfaceFormats[0].colorSpace; actualFormat = AGPU_TEXTURE_FORMAT_B8G8R8A8_UNORM; if(swapChain->format == VK_FORMAT_B8G8R8A8_SRGB) actualFormat = AGPU_TEXTURE_FORMAT_B8G8R8A8_UNORM_SRGB; // Try to select the expected format. auto wantedFormat = mapTextureFormat(createInfo->colorbuffer_format); for(size_t i = 0; i < formatCount; ++i) { auto &format = surfaceFormats[i]; if(format.format == wantedFormat) { swapChain->format = format.format; swapChain->colorSpace = format.colorSpace; actualFormat = createInfo->colorbuffer_format; break; } } } swapChain->agpuFormat = actualFormat; // Initialize the rest of the swap chain. if (!swapChain->initialize(createInfo)) { swapChain->release(); return nullptr; } return swapChain; }