VkResult WrappedVulkan::vkCreateImage( VkDevice device, const VkImageCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImage* pImage) { VkImageCreateInfo createInfo_adjusted = *pCreateInfo; createInfo_adjusted.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; VkResult ret = ObjDisp(device)->CreateImage(Unwrap(device), &createInfo_adjusted, pAllocator, pImage); // SHARING: pCreateInfo sharingMode, queueFamilyCount, pQueueFamilyIndices if(ret == VK_SUCCESS) { ResourceId id = GetResourceManager()->WrapResource(Unwrap(device), *pImage); if(m_State >= WRITING) { Chunk *chunk = NULL; { CACHE_THREAD_SERIALISER(); SCOPED_SERIALISE_CONTEXT(CREATE_IMAGE); Serialise_vkCreateImage(localSerialiser, device, pCreateInfo, NULL, pImage); chunk = scope.Get(); } VkResourceRecord *record = GetResourceManager()->AddResourceRecord(*pImage); record->AddChunk(chunk); if(pCreateInfo->flags & (VK_IMAGE_CREATE_SPARSE_BINDING_BIT|VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT)) { record->sparseInfo = new SparseMapping(); { SCOPED_LOCK(m_CapTransitionLock); if(m_State != WRITING_CAPFRAME) GetResourceManager()->MarkDirtyResource(id); else GetResourceManager()->MarkPendingDirty(id); } if(pCreateInfo->flags & VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT) { // must record image and page dimension, and create page tables uint32_t numreqs = NUM_VK_IMAGE_ASPECTS; VkSparseImageMemoryRequirements reqs[NUM_VK_IMAGE_ASPECTS]; ObjDisp(device)->GetImageSparseMemoryRequirements(Unwrap(device), Unwrap(*pImage), &numreqs, reqs); RDCASSERT(numreqs > 0); record->sparseInfo->pagedim = reqs[0].formatProperties.imageGranularity; record->sparseInfo->imgdim = pCreateInfo->extent; record->sparseInfo->imgdim.width /= record->sparseInfo->pagedim.width; record->sparseInfo->imgdim.height /= record->sparseInfo->pagedim.height; record->sparseInfo->imgdim.depth /= record->sparseInfo->pagedim.depth; uint32_t numpages = record->sparseInfo->imgdim.width*record->sparseInfo->imgdim.height*record->sparseInfo->imgdim.depth; for(uint32_t i=0; i < numreqs; i++) { // assume all page sizes are the same for all aspects RDCASSERT(record->sparseInfo->pagedim.width == reqs[i].formatProperties.imageGranularity.width && record->sparseInfo->pagedim.height == reqs[i].formatProperties.imageGranularity.height && record->sparseInfo->pagedim.depth == reqs[i].formatProperties.imageGranularity.depth); int a=0; for(; a < NUM_VK_IMAGE_ASPECTS; a++) if(reqs[i].formatProperties.aspectMask & (1<<a)) break; record->sparseInfo->pages[a] = new pair<VkDeviceMemory, VkDeviceSize>[numpages]; } } else { // don't have to do anything, image is opaque and must be fully bound, just need // to track the memory bindings. } } } else { GetResourceManager()->AddLiveResource(id, *pImage); m_CreationInfo.m_Image[id].Init(GetResourceManager(), m_CreationInfo, pCreateInfo); } VkImageSubresourceRange range; range.baseMipLevel = range.baseArrayLayer = 0; range.levelCount = pCreateInfo->mipLevels; range.layerCount = pCreateInfo->arrayLayers; if(pCreateInfo->imageType == VK_IMAGE_TYPE_3D) range.layerCount = pCreateInfo->extent.depth; ImageLayouts *layout = NULL; { SCOPED_LOCK(m_ImageLayoutsLock); layout = &m_ImageLayouts[id]; } layout->layerCount = pCreateInfo->arrayLayers; layout->levelCount = pCreateInfo->mipLevels; layout->extent = pCreateInfo->extent; layout->format = pCreateInfo->format; layout->subresourceStates.clear(); range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; if(IsDepthOnlyFormat(pCreateInfo->format)) range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; else if(IsDepthStencilFormat(pCreateInfo->format)) range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT|VK_IMAGE_ASPECT_STENCIL_BIT; layout->subresourceStates.push_back(ImageRegionState(range, UNKNOWN_PREV_IMG_LAYOUT, VK_IMAGE_LAYOUT_UNDEFINED)); } return ret; }
bool WrappedVulkan::Serialise_vkCreateImage( Serialiser* localSerialiser, VkDevice device, const VkImageCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImage* pImage) { SERIALISE_ELEMENT(ResourceId, devId, GetResID(device)); SERIALISE_ELEMENT(VkImageCreateInfo, info, *pCreateInfo); SERIALISE_ELEMENT(ResourceId, id, GetResID(*pImage)); if(m_State == READING) { device = GetResourceManager()->GetLiveHandle<VkDevice>(devId); VkImage img = VK_NULL_HANDLE; VkImageUsageFlags origusage = info.usage; // ensure we can always display and copy from/to textures info.usage |= VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT; VkResult ret = ObjDisp(device)->CreateImage(Unwrap(device), &info, NULL, &img); info.usage = origusage; if(ret != VK_SUCCESS) { RDCERR("Failed on resource serialise-creation, VkResult: 0x%08x", ret); } else { ResourceId live = GetResourceManager()->WrapResource(Unwrap(device), img); GetResourceManager()->AddLiveResource(id, img); m_CreationInfo.m_Image[live].Init(GetResourceManager(), m_CreationInfo, &info); VkImageSubresourceRange range; range.baseMipLevel = range.baseArrayLayer = 0; range.levelCount = info.mipLevels; range.layerCount = info.arrayLayers; if(info.imageType == VK_IMAGE_TYPE_3D) range.layerCount = info.extent.depth; ImageLayouts &layouts = m_ImageLayouts[live]; layouts.subresourceStates.clear(); layouts.layerCount = info.arrayLayers; layouts.levelCount = info.mipLevels; layouts.extent = info.extent; layouts.format = info.format; range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; if(IsDepthOnlyFormat(info.format)) range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; else if(IsDepthStencilFormat(info.format)) range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT|VK_IMAGE_ASPECT_STENCIL_BIT; layouts.subresourceStates.push_back(ImageRegionState(range, UNKNOWN_PREV_IMG_LAYOUT, VK_IMAGE_LAYOUT_UNDEFINED)); } } return true; }
bool VulkanTexture::CreateDirect(int w, int h, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage, const VkComponentMapping *mapping) { Wipe(); VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer(); tex_width = w; tex_height = h; numMips_ = numMips; format_ = format; VkImageAspectFlags aspect = IsDepthStencilFormat(format) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; VkImageCreateInfo image_create_info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; image_create_info.imageType = VK_IMAGE_TYPE_2D; image_create_info.format = format_; image_create_info.extent.width = tex_width; image_create_info.extent.height = tex_height; image_create_info.extent.depth = 1; image_create_info.mipLevels = numMips; image_create_info.arrayLayers = 1; image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; image_create_info.flags = 0; image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; image_create_info.usage = usage; if (initialLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) { image_create_info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; } else { image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; } VkResult res = vkCreateImage(vulkan_->GetDevice(), &image_create_info, NULL, &image); if (res != VK_SUCCESS) { assert(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS); return false; } // Write a command to transition the image to the requested layout, if it's not already that layout. if (initialLayout != VK_IMAGE_LAYOUT_UNDEFINED && initialLayout != VK_IMAGE_LAYOUT_PREINITIALIZED) { TransitionImageLayout(cmd, image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, initialLayout); } vkGetImageMemoryRequirements(vulkan_->GetDevice(), image, &mem_reqs); if (allocator_) { offset_ = allocator_->Allocate(mem_reqs, &mem); if (offset_ == VulkanDeviceAllocator::ALLOCATE_FAILED) { return false; } } else { VkMemoryAllocateInfo mem_alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; mem_alloc.memoryTypeIndex = 0; mem_alloc.allocationSize = mem_reqs.size; // Find memory type - don't specify any mapping requirements bool pass = vulkan_->MemoryTypeFromProperties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &mem_alloc.memoryTypeIndex); assert(pass); res = vkAllocateMemory(vulkan_->GetDevice(), &mem_alloc, NULL, &mem); if (res != VK_SUCCESS) { assert(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS); return false; } offset_ = 0; } res = vkBindImageMemory(vulkan_->GetDevice(), image, mem, offset_); if (res != VK_SUCCESS) { assert(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS); return false; } // Create the view while we're at it. VkImageViewCreateInfo view_info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; view_info.image = image; view_info.viewType = VK_IMAGE_VIEW_TYPE_2D; view_info.format = format_; if (mapping) { view_info.components = *mapping; } else { view_info.components.r = VK_COMPONENT_SWIZZLE_R; view_info.components.g = VK_COMPONENT_SWIZZLE_G; view_info.components.b = VK_COMPONENT_SWIZZLE_B; view_info.components.a = VK_COMPONENT_SWIZZLE_A; } view_info.subresourceRange.aspectMask = aspect; view_info.subresourceRange.baseMipLevel = 0; view_info.subresourceRange.levelCount = numMips; view_info.subresourceRange.baseArrayLayer = 0; view_info.subresourceRange.layerCount = 1; res = vkCreateImageView(vulkan_->GetDevice(), &view_info, NULL, &view); if (res != VK_SUCCESS) { assert(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS); return false; } return true; }