Split out VulkanTexture from VulkanContext.cpp/h into VulkanImage.cpp/h

This commit is contained in:
Henrik Rydgard 2016-03-17 11:56:43 +01:00
parent 3744008d1f
commit da50370328
19 changed files with 549 additions and 473 deletions

View File

@ -242,6 +242,7 @@
<ClInclude Include="Timer.h" />
<ClInclude Include="Vulkan\SPIRVDisasm.h" />
<ClInclude Include="Vulkan\VulkanContext.h" />
<ClInclude Include="Vulkan\VulkanImage.h" />
<ClInclude Include="Vulkan\VulkanLoader.h" />
<ClInclude Include="x64Analyzer.h" />
<ClInclude Include="x64Emitter.h" />
@ -313,6 +314,7 @@
<ClCompile Include="Timer.cpp" />
<ClCompile Include="Vulkan\SPIRVDisasm.cpp" />
<ClCompile Include="Vulkan\VulkanContext.cpp" />
<ClCompile Include="Vulkan\VulkanImage.cpp" />
<ClCompile Include="Vulkan\VulkanLoader.cpp" />
<ClCompile Include="x64Analyzer.cpp" />
<ClCompile Include="x64Emitter.cpp" />

View File

@ -67,6 +67,9 @@
<ClInclude Include="Vulkan\VulkanContext.h">
<Filter>Vulkan</Filter>
</ClInclude>
<ClInclude Include="Vulkan\VulkanImage.h">
<Filter>Vulkan</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp" />
@ -121,6 +124,9 @@
<ClCompile Include="Vulkan\VulkanContext.cpp">
<Filter>Vulkan</Filter>
</ClCompile>
<ClCompile Include="Vulkan\VulkanImage.cpp">
<Filter>Vulkan</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="CMakeLists.txt" />

View File

@ -42,6 +42,8 @@ static const char *validationLayers[] = {
*/
};
static VkBool32 CheckLayers(const std::vector<layer_properties> &layer_props, const std::vector<const char *> &layer_names);
VulkanContext::VulkanContext(const char *app_name, int app_ver, uint32_t flags)
: device_(nullptr),
gfx_queue_(VK_NULL_HANDLE),
@ -581,7 +583,7 @@ VkResult VulkanContext::InitDeviceLayerProperties() {
* Return 1 (true) if all layer names specified in check_names
* can be found in given layer properties.
*/
VkBool32 CheckLayers(const std::vector<layer_properties> &layer_props, const std::vector<const char *> &layer_names) {
static VkBool32 CheckLayers(const std::vector<layer_properties> &layer_props, const std::vector<const char *> &layer_names) {
uint32_t check_count = (uint32_t)layer_names.size();
uint32_t layer_count = (uint32_t)layer_props.size();
for (uint32_t i = 0; i < check_count; i++) {
@ -1188,361 +1190,6 @@ void VulkanContext::InitCommandPool() {
assert(res == VK_SUCCESS);
}
VkResult VulkanTexture::Create(int w, int h, VkFormat format) {
tex_width = w;
tex_height = h;
format_ = format;
VkFormatProperties formatProps;
vkGetPhysicalDeviceFormatProperties(vulkan_->GetPhysicalDevice(), format, &formatProps);
// See if we can use a linear tiled image for a texture, if not, we will need a staging image for the texture data.
// Linear tiling is usually only supported for 2D non-array textures.
// needStaging = (!(formatProps.linearTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) ? true : false;
// Always stage.
needStaging = true;
return VK_SUCCESS;
}
void VulkanTexture::CreateMappableImage() {
// If we already have a mappableImage, forget it.
if (mappableImage) {
vulkan_->Delete().QueueDeleteImage(mappableImage);
mappableImage = VK_NULL_HANDLE;
}
if (mappableMemory) {
vulkan_->Delete().QueueDeleteDeviceMemory(mappableMemory);
mappableMemory = VK_NULL_HANDLE;
}
bool U_ASSERT_ONLY pass;
VkImageCreateInfo image_create_info = {};
image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
image_create_info.pNext = NULL;
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 = 1;
image_create_info.arrayLayers = 1;
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_create_info.tiling = VK_IMAGE_TILING_LINEAR;
image_create_info.usage = needStaging ? VK_IMAGE_USAGE_TRANSFER_SRC_BIT : VK_IMAGE_USAGE_SAMPLED_BIT;
image_create_info.queueFamilyIndexCount = 0;
image_create_info.pQueueFamilyIndices = NULL;
image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
image_create_info.flags = 0;
image_create_info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
VkMemoryAllocateInfo mem_alloc = {};
mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
mem_alloc.pNext = NULL;
mem_alloc.allocationSize = 0;
mem_alloc.memoryTypeIndex = 0;
// Create a mappable image. It will be the texture if linear images are ok to be textures
// or it will be the staging image if they are not.
VkResult res = vkCreateImage(vulkan_->GetDevice(), &image_create_info, NULL, &mappableImage);
assert(res == VK_SUCCESS);
vkGetImageMemoryRequirements(vulkan_->GetDevice(), mappableImage, &mem_reqs);
assert(res == VK_SUCCESS);
mem_alloc.allocationSize = mem_reqs.size;
// Find the memory type that is host mappable.
pass = vulkan_->MemoryTypeFromProperties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &mem_alloc.memoryTypeIndex);
assert(pass);
res = vkAllocateMemory(vulkan_->GetDevice(), &mem_alloc, NULL, &mappableMemory);
assert(res == VK_SUCCESS);
res = vkBindImageMemory(vulkan_->GetDevice(), mappableImage, mappableMemory, 0);
assert(res == VK_SUCCESS);
}
uint8_t *VulkanTexture::Lock(int level, int *rowPitch) {
CreateMappableImage();
VkImageSubresource subres = {};
subres.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
subres.mipLevel = 0;
subres.arrayLayer = 0;
VkSubresourceLayout layout;
void *data;
// Get the subresource layout so we know what the row pitch is
vkGetImageSubresourceLayout(vulkan_->GetDevice(), mappableImage, &subres, &layout);
VkResult res = vkMapMemory(vulkan_->GetDevice(), mappableMemory, layout.offset, layout.size, 0, &data);
assert(res == VK_SUCCESS);
*rowPitch = (int)layout.rowPitch;
return (uint8_t *)data;
}
void VulkanTexture::Unlock() {
vkUnmapMemory(vulkan_->GetDevice(), mappableMemory);
VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
// if we already have an image, queue it for destruction and forget it.
Wipe();
if (!needStaging) {
// If we can use the linear tiled image as a texture, just do it
image = mappableImage;
mem = mappableMemory;
TransitionImageLayout(cmd, image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
// Make sure we don't accidentally delete the main image.
mappableImage = VK_NULL_HANDLE;
mappableMemory = VK_NULL_HANDLE;
} else {
VkImageCreateInfo image_create_info = {};
image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
image_create_info.pNext = NULL;
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 = 1;
image_create_info.arrayLayers = 1;
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_create_info.queueFamilyIndexCount = 0;
image_create_info.pQueueFamilyIndices = NULL;
image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
image_create_info.flags = 0;
// The mappable image cannot be our texture, so create an optimally tiled image and blit to it
image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VkResult res = vkCreateImage(vulkan_->GetDevice(), &image_create_info, NULL, &image);
assert(res == VK_SUCCESS);
vkGetImageMemoryRequirements(vulkan_->GetDevice(), image, &mem_reqs);
VkMemoryAllocateInfo mem_alloc = {};
mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
mem_alloc.pNext = NULL;
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);
assert(res == VK_SUCCESS);
res = vkBindImageMemory(vulkan_->GetDevice(), image, mem, 0);
assert(res == VK_SUCCESS);
// Since we're going to blit from the mappable image, set its layout to SOURCE_OPTIMAL
TransitionImageLayout(cmd, mappableImage,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_PREINITIALIZED,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
TransitionImageLayout(cmd, image,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
VkImageCopy copy_region;
copy_region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copy_region.srcSubresource.mipLevel = 0;
copy_region.srcSubresource.baseArrayLayer = 0;
copy_region.srcSubresource.layerCount = 1;
copy_region.srcOffset.x = 0;
copy_region.srcOffset.y = 0;
copy_region.srcOffset.z = 0;
copy_region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copy_region.dstSubresource.mipLevel = 0;
copy_region.dstSubresource.baseArrayLayer = 0;
copy_region.dstSubresource.layerCount = 1;
copy_region.dstOffset.x = 0;
copy_region.dstOffset.y = 0;
copy_region.dstOffset.z = 0;
copy_region.extent.width = tex_width;
copy_region.extent.height = tex_height;
copy_region.extent.depth = 1;
// Put the copy command into the command buffer
vkCmdCopyImage(cmd,
mappableImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1, &copy_region);
assert(res == VK_SUCCESS);
// Set the layout for the texture image from DESTINATION_OPTIMAL to SHADER_READ_ONLY
TransitionImageLayout(cmd, image,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
// Then drop the temporary mappable image - although should not be necessary...
vulkan_->Delete().QueueDeleteImage(mappableImage);
vulkan_->Delete().QueueDeleteDeviceMemory(mappableMemory);
mappableImage = VK_NULL_HANDLE;
mappableMemory = VK_NULL_HANDLE;
}
VkImageViewCreateInfo view_info = {};
view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
view_info.pNext = NULL;
view_info.image = VK_NULL_HANDLE;
view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
view_info.format = format_;
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 = VK_IMAGE_ASPECT_COLOR_BIT;
view_info.subresourceRange.baseMipLevel = 0;
view_info.subresourceRange.levelCount = 1;
view_info.subresourceRange.baseArrayLayer = 0;
view_info.subresourceRange.layerCount = 1;
view_info.image = image;
VkResult res = vkCreateImageView(vulkan_->GetDevice(), &view_info, NULL, &view);
assert(res == VK_SUCCESS);
}
void VulkanTexture::Wipe() {
if (image) {
vulkan_->Delete().QueueDeleteImage(image);
image = VK_NULL_HANDLE;
}
if (view) {
vulkan_->Delete().QueueDeleteImageView(view);
view = VK_NULL_HANDLE;
}
if (mem) {
vulkan_->Delete().QueueDeleteDeviceMemory(mem);
mem = VK_NULL_HANDLE;
}
}
void VulkanTexture::CreateDirect(int w, int h, int numMips, VkFormat format) {
Wipe();
VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
tex_width = w;
tex_height = h;
numMips_ = numMips;
format_ = format;
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 = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VkResult res = vkCreateImage(vulkan_->GetDevice(), &image_create_info, NULL, &image);
assert(res == VK_SUCCESS);
vkGetImageMemoryRequirements(vulkan_->GetDevice(), image, &mem_reqs);
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);
assert(res == VK_SUCCESS);
res = vkBindImageMemory(vulkan_->GetDevice(), image, mem, 0);
assert(res == VK_SUCCESS);
// Since we're going to blit to the target, set its layout to TRANSFER_DST
TransitionImageLayout(cmd, image,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
// Create the view while we're at it.
VkImageViewCreateInfo view_info = {};
view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
view_info.pNext = NULL;
view_info.image = VK_NULL_HANDLE;
view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
view_info.format = format_;
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 = VK_IMAGE_ASPECT_COLOR_BIT;
view_info.subresourceRange.baseMipLevel = 0;
view_info.subresourceRange.levelCount = numMips;
view_info.subresourceRange.baseArrayLayer = 0;
view_info.subresourceRange.layerCount = 1;
view_info.image = image;
res = vkCreateImageView(vulkan_->GetDevice(), &view_info, NULL, &view);
assert(res == VK_SUCCESS);
}
void VulkanTexture::UploadMip(int mip, int mipWidth, int mipHeight, VkBuffer buffer, size_t offset, size_t rowLength) {
VkBufferImageCopy copy_region = {};
copy_region.bufferOffset = offset;
copy_region.bufferRowLength = (uint32_t)rowLength;
copy_region.bufferImageHeight = 0; // 2D
copy_region.imageExtent.width = mipWidth;
copy_region.imageExtent.height = mipHeight;
copy_region.imageExtent.depth = 1;
copy_region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copy_region.imageSubresource.mipLevel = mip;
copy_region.imageSubresource.baseArrayLayer = 0;
copy_region.imageSubresource.layerCount = 1;
VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
vkCmdCopyBufferToImage(cmd, buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copy_region);
}
void VulkanTexture::EndCreate() {
VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
TransitionImageLayout(cmd, image,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}
void VulkanTexture::Destroy() {
if (view) {
vulkan_->Delete().QueueDeleteImageView(view);
}
if (image) {
vulkan_->Delete().QueueDeleteImage(image);
if (mappableImage == image) {
mappableImage = VK_NULL_HANDLE;
}
}
if (mem) {
vulkan_->Delete().QueueDeleteDeviceMemory(mem);
if (mappableMemory == mem) {
mappableMemory = VK_NULL_HANDLE;
}
}
view = VK_NULL_HANDLE;
image = VK_NULL_HANDLE;
mem = VK_NULL_HANDLE;
}
VkFence VulkanContext::CreateFence(bool presignalled) {
VkFence fence;
VkFenceCreateInfo fenceInfo;
@ -1889,22 +1536,3 @@ const char *VulkanResultToString(VkResult res) {
void VulkanAssertImpl(VkResult check, const char *function, const char *file, int line) {
const char *error = "(none)";
}
void VulkanFramebuffer::Create(VulkanContext *vulkan, int w, int h, VkFormat format) {
}
// void TransitionToImage()
void VulkanFramebuffer::BeginPass(VkCommandBuffer cmd) {
}
void VulkanFramebuffer::EndPass(VkCommandBuffer cmd) {
}
void VulkanFramebuffer::TransitionToTexture(VkCommandBuffer cmd) {
}
VkImageView VulkanFramebuffer::GetColorImageView() {
return VK_NULL_HANDLE;
}

View File

@ -340,71 +340,6 @@ private:
std::vector<VkCommandBuffer> cmdQueue_;
};
// Wrapper around what you need to use a texture.
// Not very optimal - if you have many small textures you should use other strategies.
// Only supports simple 2D textures for now. Mipmap support will be added later.
class VulkanTexture {
public:
VulkanTexture(VulkanContext *vulkan)
: vulkan_(vulkan), image(VK_NULL_HANDLE), mem(VK_NULL_HANDLE), view(VK_NULL_HANDLE),
tex_width(0), tex_height(0), numMips_(1), format_(VK_FORMAT_UNDEFINED),
mappableImage(VK_NULL_HANDLE), mappableMemory(VK_NULL_HANDLE), needStaging(false) {
memset(&mem_reqs, 0, sizeof(mem_reqs));
}
~VulkanTexture() {
Destroy();
}
// Simple usage - no cleverness, no mipmaps.
// Always call Create, Lock, Unlock. Unlock performs the upload if necessary.
// Can later Lock and Unlock again. This cannot change the format. Create cannot
// be called a second time without recreating the texture object until Destroy has
// been called.
VkResult Create(int w, int h, VkFormat format);
uint8_t *Lock(int level, int *rowPitch);
void Unlock();
// Fast uploads from buffer. Mipmaps supported.
void CreateDirect(int w, int h, int numMips, VkFormat format);
void UploadMip(int mip, int mipWidth, int mipHeight, VkBuffer buffer, size_t offset, size_t rowLength); // rowLength is in pixels
void EndCreate();
int GetNumMips() const { return numMips_; }
void Destroy();
VkImageView GetImageView() const { return view; }
private:
void CreateMappableImage();
void Wipe();
VulkanContext *vulkan_;
VkImage image;
VkDeviceMemory mem;
VkImageView view;
int32_t tex_width, tex_height, numMips_;
VkFormat format_;
VkImage mappableImage;
VkDeviceMemory mappableMemory;
VkMemoryRequirements mem_reqs;
bool needStaging;
};
// Placeholder
class VulkanFramebuffer {
public:
void Create(VulkanContext *vulkan, int w, int h, VkFormat format);
void BeginPass(VkCommandBuffer cmd);
void EndPass(VkCommandBuffer cmd);
void TransitionToTexture(VkCommandBuffer cmd);
VkImageView GetColorImageView();
private:
VkImage image_;
VkFramebuffer framebuffer_;
};
// Use these to push vertex, index and uniform data. Generally you'll have two of these
// and alternate on each frame.
// TODO: Make it possible to suballocate pushbuffers from a large DeviceMemory block.
@ -505,16 +440,8 @@ private:
uint8_t *writePtr_;
};
VkBool32 CheckLayers(const std::vector<layer_properties> &layer_props, const std::vector<const char *> &layer_names);
// Stand-alone utility functions
void VulkanBeginCommandBuffer(VkCommandBuffer cmd);
void init_glslang();
void finalize_glslang();
bool GLSLtoSPV(const VkShaderStageFlagBits shader_type, const char *pshader, std::vector<uint32_t> &spirv, std::string *errorMessage = nullptr);
void TransitionImageLayout(
VkCommandBuffer cmd,
VkImage image,
@ -522,5 +449,10 @@ void TransitionImageLayout(
VkImageLayout old_image_layout,
VkImageLayout new_image_layout);
// GLSL compiler
void init_glslang();
void finalize_glslang();
bool GLSLtoSPV(const VkShaderStageFlagBits shader_type, const char *pshader, std::vector<uint32_t> &spirv, std::string *errorMessage = nullptr);
#endif // UTIL_INIT

View File

@ -0,0 +1,356 @@
#include "Common/Vulkan/VulkanImage.h"
VkResult VulkanTexture::Create(int w, int h, VkFormat format) {
tex_width = w;
tex_height = h;
format_ = format;
VkFormatProperties formatProps;
vkGetPhysicalDeviceFormatProperties(vulkan_->GetPhysicalDevice(), format, &formatProps);
// See if we can use a linear tiled image for a texture, if not, we will need a staging image for the texture data.
// Linear tiling is usually only supported for 2D non-array textures.
// needStaging = (!(formatProps.linearTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) ? true : false;
// Always stage.
needStaging = true;
return VK_SUCCESS;
}
void VulkanTexture::CreateMappableImage() {
// If we already have a mappableImage, forget it.
if (mappableImage) {
vulkan_->Delete().QueueDeleteImage(mappableImage);
mappableImage = VK_NULL_HANDLE;
}
if (mappableMemory) {
vulkan_->Delete().QueueDeleteDeviceMemory(mappableMemory);
mappableMemory = VK_NULL_HANDLE;
}
bool U_ASSERT_ONLY pass;
VkImageCreateInfo image_create_info = {};
image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
image_create_info.pNext = NULL;
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 = 1;
image_create_info.arrayLayers = 1;
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_create_info.tiling = VK_IMAGE_TILING_LINEAR;
image_create_info.usage = needStaging ? VK_IMAGE_USAGE_TRANSFER_SRC_BIT : VK_IMAGE_USAGE_SAMPLED_BIT;
image_create_info.queueFamilyIndexCount = 0;
image_create_info.pQueueFamilyIndices = NULL;
image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
image_create_info.flags = 0;
image_create_info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
VkMemoryAllocateInfo mem_alloc = {};
mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
mem_alloc.pNext = NULL;
mem_alloc.allocationSize = 0;
mem_alloc.memoryTypeIndex = 0;
// Create a mappable image. It will be the texture if linear images are ok to be textures
// or it will be the staging image if they are not.
VkResult res = vkCreateImage(vulkan_->GetDevice(), &image_create_info, NULL, &mappableImage);
assert(res == VK_SUCCESS);
vkGetImageMemoryRequirements(vulkan_->GetDevice(), mappableImage, &mem_reqs);
assert(res == VK_SUCCESS);
mem_alloc.allocationSize = mem_reqs.size;
// Find the memory type that is host mappable.
pass = vulkan_->MemoryTypeFromProperties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &mem_alloc.memoryTypeIndex);
assert(pass);
res = vkAllocateMemory(vulkan_->GetDevice(), &mem_alloc, NULL, &mappableMemory);
assert(res == VK_SUCCESS);
res = vkBindImageMemory(vulkan_->GetDevice(), mappableImage, mappableMemory, 0);
assert(res == VK_SUCCESS);
}
uint8_t *VulkanTexture::Lock(int level, int *rowPitch) {
CreateMappableImage();
VkImageSubresource subres = {};
subres.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
subres.mipLevel = 0;
subres.arrayLayer = 0;
VkSubresourceLayout layout;
void *data;
// Get the subresource layout so we know what the row pitch is
vkGetImageSubresourceLayout(vulkan_->GetDevice(), mappableImage, &subres, &layout);
VkResult res = vkMapMemory(vulkan_->GetDevice(), mappableMemory, layout.offset, layout.size, 0, &data);
assert(res == VK_SUCCESS);
*rowPitch = (int)layout.rowPitch;
return (uint8_t *)data;
}
void VulkanTexture::Unlock() {
vkUnmapMemory(vulkan_->GetDevice(), mappableMemory);
VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
// if we already have an image, queue it for destruction and forget it.
Wipe();
if (!needStaging) {
// If we can use the linear tiled image as a texture, just do it
image = mappableImage;
mem = mappableMemory;
TransitionImageLayout(cmd, image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
// Make sure we don't accidentally delete the main image.
mappableImage = VK_NULL_HANDLE;
mappableMemory = VK_NULL_HANDLE;
} else {
VkImageCreateInfo image_create_info = {};
image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
image_create_info.pNext = NULL;
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 = 1;
image_create_info.arrayLayers = 1;
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_create_info.queueFamilyIndexCount = 0;
image_create_info.pQueueFamilyIndices = NULL;
image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
image_create_info.flags = 0;
// The mappable image cannot be our texture, so create an optimally tiled image and blit to it
image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VkResult res = vkCreateImage(vulkan_->GetDevice(), &image_create_info, NULL, &image);
assert(res == VK_SUCCESS);
vkGetImageMemoryRequirements(vulkan_->GetDevice(), image, &mem_reqs);
VkMemoryAllocateInfo mem_alloc = {};
mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
mem_alloc.pNext = NULL;
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);
assert(res == VK_SUCCESS);
res = vkBindImageMemory(vulkan_->GetDevice(), image, mem, 0);
assert(res == VK_SUCCESS);
// Since we're going to blit from the mappable image, set its layout to SOURCE_OPTIMAL
TransitionImageLayout(cmd, mappableImage,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_PREINITIALIZED,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
TransitionImageLayout(cmd, image,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
VkImageCopy copy_region;
copy_region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copy_region.srcSubresource.mipLevel = 0;
copy_region.srcSubresource.baseArrayLayer = 0;
copy_region.srcSubresource.layerCount = 1;
copy_region.srcOffset.x = 0;
copy_region.srcOffset.y = 0;
copy_region.srcOffset.z = 0;
copy_region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copy_region.dstSubresource.mipLevel = 0;
copy_region.dstSubresource.baseArrayLayer = 0;
copy_region.dstSubresource.layerCount = 1;
copy_region.dstOffset.x = 0;
copy_region.dstOffset.y = 0;
copy_region.dstOffset.z = 0;
copy_region.extent.width = tex_width;
copy_region.extent.height = tex_height;
copy_region.extent.depth = 1;
// Put the copy command into the command buffer
vkCmdCopyImage(cmd,
mappableImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1, &copy_region);
assert(res == VK_SUCCESS);
// Set the layout for the texture image from DESTINATION_OPTIMAL to SHADER_READ_ONLY
TransitionImageLayout(cmd, image,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
// Then drop the temporary mappable image - although should not be necessary...
vulkan_->Delete().QueueDeleteImage(mappableImage);
vulkan_->Delete().QueueDeleteDeviceMemory(mappableMemory);
mappableImage = VK_NULL_HANDLE;
mappableMemory = VK_NULL_HANDLE;
}
VkImageViewCreateInfo view_info = {};
view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
view_info.pNext = NULL;
view_info.image = VK_NULL_HANDLE;
view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
view_info.format = format_;
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 = VK_IMAGE_ASPECT_COLOR_BIT;
view_info.subresourceRange.baseMipLevel = 0;
view_info.subresourceRange.levelCount = 1;
view_info.subresourceRange.baseArrayLayer = 0;
view_info.subresourceRange.layerCount = 1;
view_info.image = image;
VkResult res = vkCreateImageView(vulkan_->GetDevice(), &view_info, NULL, &view);
assert(res == VK_SUCCESS);
}
void VulkanTexture::Wipe() {
if (image) {
vulkan_->Delete().QueueDeleteImage(image);
image = VK_NULL_HANDLE;
}
if (view) {
vulkan_->Delete().QueueDeleteImageView(view);
view = VK_NULL_HANDLE;
}
if (mem) {
vulkan_->Delete().QueueDeleteDeviceMemory(mem);
mem = VK_NULL_HANDLE;
}
}
void VulkanTexture::CreateDirect(int w, int h, int numMips, VkFormat format, VkImageUsageFlags usage) {
Wipe();
VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
tex_width = w;
tex_height = h;
numMips_ = numMips;
format_ = format;
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 = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VkResult res = vkCreateImage(vulkan_->GetDevice(), &image_create_info, NULL, &image);
assert(res == VK_SUCCESS);
vkGetImageMemoryRequirements(vulkan_->GetDevice(), image, &mem_reqs);
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);
assert(res == VK_SUCCESS);
res = vkBindImageMemory(vulkan_->GetDevice(), image, mem, 0);
assert(res == VK_SUCCESS);
// Since we're going to blit to the target, set its layout to TRANSFER_DST
TransitionImageLayout(cmd, image,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
// Create the view while we're at it.
VkImageViewCreateInfo view_info = {};
view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
view_info.pNext = NULL;
view_info.image = VK_NULL_HANDLE;
view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
view_info.format = format_;
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 = VK_IMAGE_ASPECT_COLOR_BIT;
view_info.subresourceRange.baseMipLevel = 0;
view_info.subresourceRange.levelCount = numMips;
view_info.subresourceRange.baseArrayLayer = 0;
view_info.subresourceRange.layerCount = 1;
view_info.image = image;
res = vkCreateImageView(vulkan_->GetDevice(), &view_info, NULL, &view);
assert(res == VK_SUCCESS);
}
void VulkanTexture::UploadMip(int mip, int mipWidth, int mipHeight, VkBuffer buffer, size_t offset, size_t rowLength) {
VkBufferImageCopy copy_region = {};
copy_region.bufferOffset = offset;
copy_region.bufferRowLength = (uint32_t)rowLength;
copy_region.bufferImageHeight = 0; // 2D
copy_region.imageExtent.width = mipWidth;
copy_region.imageExtent.height = mipHeight;
copy_region.imageExtent.depth = 1;
copy_region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copy_region.imageSubresource.mipLevel = mip;
copy_region.imageSubresource.baseArrayLayer = 0;
copy_region.imageSubresource.layerCount = 1;
VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
vkCmdCopyBufferToImage(cmd, buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copy_region);
}
void VulkanTexture::EndCreate() {
VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
TransitionImageLayout(cmd, image,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}
void VulkanTexture::Destroy() {
if (view) {
vulkan_->Delete().QueueDeleteImageView(view);
}
if (image) {
vulkan_->Delete().QueueDeleteImage(image);
if (mappableImage == image) {
mappableImage = VK_NULL_HANDLE;
}
}
if (mem) {
vulkan_->Delete().QueueDeleteDeviceMemory(mem);
if (mappableMemory == mem) {
mappableMemory = VK_NULL_HANDLE;
}
}
view = VK_NULL_HANDLE;
image = VK_NULL_HANDLE;
mem = VK_NULL_HANDLE;
}

View File

@ -0,0 +1,50 @@
#pragma once
#include "Common/Vulkan/VulkanContext.h"
// Wrapper around what you need to use a texture.
// Not very optimal - if you have many small textures you should use other strategies.
class VulkanTexture {
public:
VulkanTexture(VulkanContext *vulkan)
: vulkan_(vulkan), image(VK_NULL_HANDLE), mem(VK_NULL_HANDLE), view(VK_NULL_HANDLE),
tex_width(0), tex_height(0), numMips_(1), format_(VK_FORMAT_UNDEFINED),
mappableImage(VK_NULL_HANDLE), mappableMemory(VK_NULL_HANDLE), needStaging(false) {
memset(&mem_reqs, 0, sizeof(mem_reqs));
}
~VulkanTexture() {
Destroy();
}
// Simple usage - no cleverness, no mipmaps.
// Always call Create, Lock, Unlock. Unlock performs the upload if necessary.
// Can later Lock and Unlock again. This cannot change the format. Create cannot
// be called a second time without recreating the texture object until Destroy has
// been called.
VkResult Create(int w, int h, VkFormat format);
uint8_t *Lock(int level, int *rowPitch);
void Unlock();
// Fast uploads from buffer. Mipmaps supported. Usage must at least include VK_IMAGE_USAGE_TRANSFER_DST_BIT in order to use UploadMip.
void CreateDirect(int w, int h, int numMips, VkFormat format, VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
void UploadMip(int mip, int mipWidth, int mipHeight, VkBuffer buffer, size_t offset, size_t rowLength); // rowLength is in pixels
void EndCreate();
int GetNumMips() const { return numMips_; }
void Destroy();
VkImageView GetImageView() const { return view; }
private:
void CreateMappableImage();
void Wipe();
VulkanContext *vulkan_;
VkImage image;
VkDeviceMemory mem;
VkImageView view;
int32_t tex_width, tex_height, numMips_;
VkFormat format_;
VkImage mappableImage;
VkDeviceMemory mappableMemory;
VkMemoryRequirements mem_reqs;
bool needStaging;
};

View File

@ -51,7 +51,7 @@ namespace DX9 {
struct FBO_DX9;
}
class VulkanFramebuffer;
class VulkanFBO;
struct VirtualFramebuffer {
int last_frame_used;
@ -87,12 +87,13 @@ struct VirtualFramebuffer {
int lastFrameNewSize;
GEBufferFormat format; // virtual, right now they are all RGBA8888
// TODO: Handle fbo and colorDepth better.
u8 colorDepth;
union {
FBO *fbo;
DX9::FBO_DX9 *fbo_dx9;
VulkanFramebuffer *fbo_vk;
VulkanFBO *fbo_vk;
};
u16 drawnWidth;

View File

@ -106,8 +106,7 @@ inline int RoundUp4(int x) {
}
// Reads decoded vertex formats in a convenient way. For software transform and debugging.
class VertexReader
{
class VertexReader {
public:
VertexReader(u8 *base, const DecVtxFormat &decFmt, int vtype) : base_(base), data_(base), decFmt_(decFmt), vtype_(vtype) {}

View File

@ -345,6 +345,7 @@
<ClCompile Include="Vulkan\TextureCacheVulkan.cpp" />
<ClCompile Include="Vulkan\TextureScalerVulkan.cpp" />
<ClCompile Include="Vulkan\VertexShaderGeneratorVulkan.cpp" />
<ClCompile Include="Vulkan\VulkanUtil.cpp" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Common\Common.vcxproj">
@ -354,4 +355,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View File

@ -458,5 +458,6 @@
<ClCompile Include="Vulkan\VertexShaderGeneratorVulkan.cpp">
<Filter>Vulkan</Filter>
</ClCompile>
<ClCompile Include="Vulkan\VulkanUtil.cpp" />
</ItemGroup>
</Project>

View File

@ -41,10 +41,12 @@
#include "GPU/GPUInterface.h"
#include "GPU/GPUState.h"
#include "Common/Vulkan/VulkanImage.h"
#include "GPU/Vulkan/FramebufferVulkan.h"
#include "GPU/Vulkan/DrawEngineVulkan.h"
#include "GPU/Vulkan/TextureCacheVulkan.h"
#include "GPU/Vulkan/ShaderManagerVulkan.h"
#include "GPU/Vulkan/VulkanUtil.h"
#include "UI/OnScreenDisplay.h"
@ -599,7 +601,7 @@ void FramebufferManagerVulkan::ResizeFramebufFBO(VirtualFramebuffer *vfb, u16 w,
return;
}
vfb->fbo_vk = new VulkanFramebuffer();
vfb->fbo_vk = new VulkanFBO();
// bo_create(vfb->renderWidth, vfb->renderHeight, 1, true, (FBOColorDepth)vfb->colorDepth);
if (old.fbo_vk) {
INFO_LOG(SCEGE, "Resizing FBO for %08x : %i x %i x %i", vfb->fb_address, w, h, vfb->format);
@ -777,7 +779,7 @@ void FramebufferManagerVulkan::BlitFramebufferDepth(VirtualFramebuffer *src, Vir
}*/
}
VulkanFramebuffer *FramebufferManagerVulkan::GetTempFBO(u16 w, u16 h, VulkanFBOColorDepth depth) {
VulkanFBO *FramebufferManagerVulkan::GetTempFBO(u16 w, u16 h, VulkanFBOColorDepth depth) {
u64 key = ((u64)depth << 32) | ((u32)w << 16) | h;
auto it = tempFBOs_.find(key);
if (it != tempFBOs_.end()) {
@ -787,7 +789,7 @@ VulkanFramebuffer *FramebufferManagerVulkan::GetTempFBO(u16 w, u16 h, VulkanFBOC
textureCache_->ForgetLastTexture();
// FBO *fbo_vk = fbo_create(w, h, 1, false, depth);
VulkanFramebuffer *fbo_vk = new VulkanFramebuffer();
VulkanFBO *fbo_vk = new VulkanFBO();
if (!fbo_vk)
return nullptr;
// fbo_bind_as_render_target(fbo_vk);

View File

@ -36,13 +36,13 @@ class DrawEngineVulkan;
class VulkanContext;
class ShaderManagerVulkan;
class VulkanTexture;
class VulkanFramebuffer;
struct PostShaderUniforms {
float texelDelta[2]; float pad[2];
float pixelDelta[2]; float pad0[2];
float time[4];
};
// Simple struct for asynchronous PBO readbacks
// TODO: Probably will need a complete redesign.
struct AsyncPBOVulkan {
@ -122,7 +122,7 @@ public:
virtual void RebindFramebuffer() override;
VulkanFramebuffer *GetTempFBO(u16 w, u16 h, VulkanFBOColorDepth depth = VK_FBO_8888);
VulkanFBO *GetTempFBO(u16 w, u16 h, VulkanFBOColorDepth depth = VK_FBO_8888);
// Cardboard Settings Calculator
struct CardboardSettings * GetCardboardSettings(struct CardboardSettings * cardboardSettings);
@ -182,7 +182,7 @@ private:
bool resized_;
struct TempFBO {
VulkanFramebuffer *fbo_vk;
VulkanFBO *fbo_vk;
int last_frame_used;
};

View File

@ -1,5 +1,4 @@
#pragma once
// Copyright (c) 2012- PPSSPP Project.
// Copyright (c) 2016- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by

View File

@ -22,13 +22,16 @@
#include "i18n/i18n.h"
#include "math/math_util.h"
#include "profiler/profiler.h"
#include "Common/Vulkan/VulkanContext.h"
#include "Common/ColorConv.h"
#include "Core/Config.h"
#include "Core/Host.h"
#include "Core/MemMap.h"
#include "Core/Reporting.h"
#include "Core/System.h"
#include "Common/Vulkan/VulkanContext.h"
#include "Common/Vulkan/VulkanImage.h"
#include "GPU/ge_constants.h"
#include "GPU/GPUState.h"
#include "GPU/Vulkan/TextureCacheVulkan.h"
@ -81,6 +84,10 @@ SamplerCache::~SamplerCache() {
}
}
CachedTextureVulkan::~CachedTextureVulkan() {
delete texture_;
}
VkSampler SamplerCache::GetOrCreateSampler(const SamplerCacheKey &key) {
auto iter = cache_.find(key);
if (iter != cache_.end()) {
@ -905,9 +912,9 @@ void TextureCacheVulkan::ApplyTextureFramebuffer(VkCommandBuffer cmd, TexCacheEn
}
if (depal) {
// VulkanTexture *clutTexture = depalShaderCache_->GetClutTexture(clutFormat, clutHash_, clutBuf_);
VulkanFramebuffer *depalFBO = framebufferManager_->GetTempFBO(framebuffer->renderWidth, framebuffer->renderHeight, VK_FBO_8888);
VulkanFBO *depalFBO = framebufferManager_->GetTempFBO(framebuffer->renderWidth, framebuffer->renderHeight, VK_FBO_8888);
depalFBO->BeginPass(cmd);
//depalFBO->BeginPass(cmd);
struct Pos {
Pos(float x_, float y_, float z_) : x(x_), y(y_), z(z_) {
@ -1018,9 +1025,9 @@ void TextureCacheVulkan::ApplyTextureFramebuffer(VkCommandBuffer cmd, TexCacheEn
glDisableVertexAttribArray(depal->a_position);
glDisableVertexAttribArray(depal->a_texcoord0);
*/
depalFBO->EndPass(cmd);
depalFBO->TransitionToTexture(cmd);
imageView = depalFBO->GetColorImageView();
//depalFBO->EndPass(cmd);
//depalFBO->TransitionToTexture(cmd);
//imageView = depalFBO->GetColorImageView();
}
/*

View File

@ -33,7 +33,7 @@ class ShaderManagerVulkan;
class DrawEngineVulkan;
class VulkanContext;
class VulkanImage;
class VulkanTexture;
struct SamplerCacheKey {
SamplerCacheKey() : fullKey(0) {}
@ -61,9 +61,8 @@ class CachedTextureVulkan {
public:
CachedTextureVulkan() : texture_(nullptr) {
}
~CachedTextureVulkan() {
delete texture_;
}
~CachedTextureVulkan();
// TODO: Switch away from VulkanImage to some kind of smart suballocating texture pool.
VulkanTexture *texture_;
};

45
GPU/Vulkan/VulkanUtil.cpp Normal file
View File

@ -0,0 +1,45 @@
// Copyright (c) 2016- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "GPU/Vulkan/VulkanUtil.h"
VulkanFBO::VulkanFBO() : color_(nullptr), depthStencil_(nullptr) {}
VulkanFBO::~VulkanFBO() {
delete color_;
delete depthStencil_;
}
void VulkanFBO::Create(VulkanContext *vulkan, VkRenderPass rp_compatible, int width, int height, VkFormat color_Format) {
color_ = new VulkanTexture(vulkan);
VkImageCreateFlags flags = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
color_->CreateDirect(width, height, 1, VK_FORMAT_R8G8B8A8_UNORM, flags | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
depthStencil_->CreateDirect(width, height, 1, VK_FORMAT_D24_UNORM_S8_UINT, flags | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
VkImageView views[2] = { color_->GetImageView(), depthStencil_->GetImageView() };
VkFramebufferCreateInfo fb = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
fb.pAttachments = views;
fb.attachmentCount = 2;
fb.flags = 0;
fb.renderPass = rp_compatible;
fb.width = width;
fb.height = height;
fb.layers = 1;
vkCreateFramebuffer(vulkan->GetDevice(), &fb, nullptr, &framebuffer_);
}

View File

@ -1,4 +1,48 @@
// Copyright (c) 2016- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once
#include "Common/Vulkan/VulkanLoader.h"
#include "Common/Vulkan/VulkanImage.h"
// Vulkan doesn't really have the concept of an FBO that owns the images,
// but it does have the concept of a framebuffer as a set of attachments.
// VulkanFBO is an approximation of the FBO concept the other backends use
// to make things as similar as possible without being suboptimal.
//
class VulkanFBO {
public:
VulkanFBO();
~VulkanFBO();
// Depth-format is chosen automatically depending on hardware support.
// Color format will be 32-bit RGBA.
void Create(VulkanContext *vulkan, VkRenderPass rp_compatible, int width, int height, VkFormat colorFormat);
VulkanTexture *GetColor() { return color_; }
VulkanTexture *GetDepthStencil() { return depthStencil_; }
VkFramebuffer GetFramebuffer() { return framebuffer_; }
private:
VulkanTexture *color_;
VulkanTexture *depthStencil_;
// This point specifically to color and depth.
VkFramebuffer framebuffer_;
};

View File

@ -127,6 +127,7 @@ EGL_FILES := \
VULKAN_FILES := \
$(SRC)/Common/Vulkan/VulkanLoader.cpp \
$(SRC)/Common/Vulkan/VulkanContext.cpp \
$(SRC)/Common/Vulkan/VulkanImage.cpp \
$(SRC)/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp \
$(SRC)/GPU/Vulkan/DrawEngineVulkan.cpp \
$(SRC)/GPU/Vulkan/FramebufferVulkan.cpp \
@ -137,7 +138,8 @@ VULKAN_FILES := \
$(SRC)/GPU/Vulkan/TextureCacheVulkan.cpp \
$(SRC)/GPU/Vulkan/TextureScalerVulkan.cpp \
$(SRC)/GPU/Vulkan/DepalettizeShaderVulkan.cpp \
$(SRC)/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp
$(SRC)/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp \
$(SRC)/GPU/Vulkan/VulkanUtil.cpp
#endif
EXEC_AND_LIB_FILES := \

View File

@ -30,7 +30,9 @@
#include "math/lin/matrix4x4.h"
#include "math/dataconv.h"
#include "thin3d/thin3d.h"
#include "Common/Vulkan/VulkanContext.h"
#include "Common/Vulkan/VulkanImage.h"
// We use a simple descriptor set for all rendering: 1 sampler, 1 texture, 1 UBO binding point.
// binding 0 - uniform data