3#include "GraphicsDeviceVK.h"
12void Cogs::TexturesVK::initialize(GraphicsDeviceVK * grapihcsDevice)
14 this->graphicsDevice = grapihcsDevice;
15 device = grapihcsDevice->device;
20 auto & texture = textures[textureHandle];
22 vkDestroyImageView(device, texture.imageView,
nullptr);
24 if (!texture.external) {
25 vkDestroyImage(device, texture.image,
nullptr);
33 VkFilter filters[] = {
40 VkSamplerMipmapMode mipModes[] = {
41 VK_SAMPLER_MIPMAP_MODE_NEAREST,
42 VK_SAMPLER_MIPMAP_MODE_LINEAR,
43 VK_SAMPLER_MIPMAP_MODE_NEAREST,
44 VK_SAMPLER_MIPMAP_MODE_LINEAR,
47 VkSamplerAddressMode addressModes[] = {
48 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
49 VK_SAMPLER_ADDRESS_MODE_REPEAT,
50 VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT,
51 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
54 VkCompareOp comp[] = {
58 VK_COMPARE_OP_LESS_OR_EQUAL,
59 VK_COMPARE_OP_GREATER,
60 VK_COMPARE_OP_NOT_EQUAL,
61 VK_COMPARE_OP_GREATER_OR_EQUAL,
65 VkSamplerCreateInfo samplerInfo = {};
66 samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
67 samplerInfo.pNext =
nullptr;
69 samplerInfo.magFilter = filters[state.
filter];
70 samplerInfo.minFilter = filters[state.
filter];
71 samplerInfo.mipmapMode = mipModes[state.
filter];
73 samplerInfo.addressModeU = addressModes[state.
addressModeS];
74 samplerInfo.addressModeV = addressModes[state.
addressModeT];
75 samplerInfo.addressModeW = addressModes[state.
addressModeW];
77 samplerInfo.compareEnable = state.
filter > 1;
80 samplerInfo.mipLodBias = 0.0f;
81 samplerInfo.minLod = 0.0f;
82 samplerInfo.maxLod = 16.0f;
84 samplerInfo.maxAnisotropy =
static_cast<float>(state.
maxAnisotropy);
87 samplerInfo.borderColor = state.
borderColor[3] == 1 ?
88 (state.
borderColor[0] == 1 ? VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE : VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK) :
89 VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
91 auto result = vkCreateSampler(device, &samplerInfo,
nullptr, &sampler.sampler);
93 if (VK_FAILED(result)) {
94 VK_LOG_ERROR(result,
"Could not load sampler.");
98 return samplers.addResource(sampler);
115 uint32_t width = desc.width;
116 uint32_t height = desc.height;
119 texture.width = width;
120 texture.height = height;
121 texture.samples = desc.samples;
122 texture.layout = VK_IMAGE_LAYOUT_UNDEFINED;
124 const auto vkFormat = Vulkan::TextureFormats[(int)desc.format];
125 texture.format = desc.format;
126 texture.vkFormat = vkFormat;
129 const bool isStaging = (desc.flags & TextureFlagsVK::Staging) != 0;
132 VkImageUsageFlags vkUsage = 0;
133 VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL;
134 VkImageLayout initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
136 if (isRenderTarget) {
137 vkUsage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
141 vkUsage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
143 texture.isDepth =
true;
146 vkUsage |= VK_IMAGE_USAGE_SAMPLED_BIT;
148 }
else if (isStaging) {
149 vkUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
150 tiling = VK_IMAGE_TILING_LINEAR;
151 initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
153 vkUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
157 VkImageCreateInfo imageCreateInfo = {};
158 imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
159 imageCreateInfo.pNext =
nullptr;
160 imageCreateInfo.initialLayout = initialLayout;
161 imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
162 imageCreateInfo.format = vkFormat;
163 imageCreateInfo.extent = { width, height, 1 };
164 imageCreateInfo.mipLevels = desc.levels;
165 imageCreateInfo.arrayLayers = desc.layers;
166 imageCreateInfo.samples = (VkSampleCountFlagBits)desc.samples;
167 imageCreateInfo.tiling = tiling;
168 imageCreateInfo.usage = vkUsage;
169 imageCreateInfo.flags = 0;
171 auto result = vkCreateImage(device, &imageCreateInfo,
nullptr, &texture.image);
173 if (VK_FAILED(result)) {
174 VK_LOG_ERROR(result,
"Could not create image.");
178 VkMemoryAllocateInfo allocateInfo = {};
179 allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
180 allocateInfo.pNext =
nullptr;
181 allocateInfo.allocationSize = 0;
182 allocateInfo.memoryTypeIndex = 0;
184 VkMemoryRequirements memoryRequirements;
185 vkGetImageMemoryRequirements(device, texture.image, &memoryRequirements);
187 VkFlags memoryFlags = isStaging ? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT : 0;
188 uint32_t typeIndex = 0;
189 graphicsDevice->getMemoryType(memoryRequirements.memoryTypeBits, memoryFlags, &typeIndex);
191 allocateInfo.allocationSize = memoryRequirements.size;
192 allocateInfo.memoryTypeIndex = typeIndex;
194 result = vkAllocateMemory(device, &allocateInfo,
nullptr, &texture.deviceMemory);
196 if (VK_FAILED(result)) {
197 VK_LOG_ERROR(result,
"Could not allocate device memory.");
201 result = vkBindImageMemory(device, texture.image, texture.deviceMemory, 0);
203 if (VK_FAILED(result)) {
204 VK_LOG_ERROR(result,
"Could not bind image memory.");
209 updateTextureData(data, desc.layers, desc.levels, texture);
212 texture.image = (VkImage)data->externalHandle;
213 texture.external =
true;
217 VkImageViewCreateInfo imageViewInfo = {};
218 imageViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
219 imageViewInfo.image = texture.image;
220 imageViewInfo.format = vkFormat;
223 VkComponentMapping swizzle = isDepth ?
224 VkComponentMapping{ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY } :
225 VkComponentMapping{ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
227 imageViewInfo.components = swizzle;
228 imageViewInfo.subresourceRange.aspectMask = isDepth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
229 imageViewInfo.subresourceRange.baseMipLevel = 0;
230 imageViewInfo.subresourceRange.levelCount = desc.levels;
231 imageViewInfo.subresourceRange.baseArrayLayer = 0;
232 imageViewInfo.subresourceRange.layerCount = desc.layers;
233 imageViewInfo.flags = 0;
234 imageViewInfo.viewType = desc.layers > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D;
236 auto result = vkCreateImageView(device, &imageViewInfo,
nullptr, &texture.imageView);
238 if (VK_FAILED(result)) {
239 VK_LOG_ERROR(result,
"Could not create image view.");
244 return textures.addResource(texture);
247void Cogs::TexturesVK::updateTextureData(
const TextureData * data,
const uint32_t arraySize,
const uint32_t numLevels,
TextureVK & texture)
249 VkImageSubresourceRange range;
250 range.aspectMask = texture.isDepth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
251 range.baseArrayLayer = 0;
252 range.baseMipLevel = 0;
253 range.layerCount = arraySize;
254 range.levelCount = numLevels;
256 setImageLayout(graphicsDevice->getCommandBuffer(),
259 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
262 for (uint32_t a = 0; a < arraySize; ++a) {
263 for (uint32_t m = 0; m < numLevels; ++m) {
264 const uint32_t index = a * numLevels + m;
266 const uint32_t width = texture.width /
static_cast<uint32_t
>(std::pow(2ul, m));
267 const uint32_t height = texture.height /
static_cast<uint32_t
>(std::pow(2ul, m));
269 auto uploadHandle = loadTexture(
nullptr, width, height, texture.format, TextureFlagsVK::Staging);
271 if (!HandleIsValid(uploadHandle)) {
272 LOG_ERROR(logger,
"Could not create staging texture.");
276 TextureVK uploadTexture = textures[uploadHandle];
278 VkImageSubresource imageSubresource = {};
279 imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
280 imageSubresource.arrayLayer = a;
281 imageSubresource.mipLevel = m;
283 VkSubresourceLayout resourceLayout;
284 vkGetImageSubresourceLayout(device, uploadTexture.image, &imageSubresource, &resourceLayout);
286 const size_t bpp = Cogs::getBlockSize(texture.format);
289 auto result = vkMapMemory(device, uploadTexture.deviceMemory, 0, VK_WHOLE_SIZE, 0, &vData);
291 if (VK_FAILED(result)) {
292 VK_LOG_ERROR(result,
"Could not map upload memory.");
295 auto mappedData =
static_cast<uint8_t *
>(vData);
296 const auto sourceData =
static_cast<const uint8_t *
>(data->getData(a, 0, m));
297 const auto sourcePitch = data->getPitch(m);
298 const auto rows = resourceLayout.size / resourceLayout.rowPitch;
300 for (
size_t i = 0; i < rows; ++i) {
301 std::memcpy(mappedData, sourceData + i * sourcePitch, sourcePitch);
302 mappedData += resourceLayout.rowPitch;
305 vkUnmapMemory(device, uploadTexture.deviceMemory);
307 setImageLayout(graphicsDevice->getCommandBuffer(),
309 VK_IMAGE_ASPECT_COLOR_BIT,
310 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
312 VkImageCopy copyRegion = {};
314 copyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
315 copyRegion.srcSubresource.baseArrayLayer = 0;
316 copyRegion.srcSubresource.mipLevel = 0;
317 copyRegion.srcSubresource.layerCount = 1;
318 copyRegion.srcOffset = { 0, 0, 0 };
320 copyRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
321 copyRegion.dstSubresource.baseArrayLayer = a;
322 copyRegion.dstSubresource.mipLevel = m;
323 copyRegion.dstSubresource.layerCount = 1;
324 copyRegion.dstOffset = { 0, 0, 0 };
326 copyRegion.extent.width = width;
327 copyRegion.extent.height = height;
328 copyRegion.extent.depth = 1;
331 graphicsDevice->getCommandBuffer(),
332 uploadTexture.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
333 texture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
338 setImageLayout(graphicsDevice->getCommandBuffer(),
341 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
Log implementation class.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
static const Handle_t InvalidHandle
Represents an invalid handle.
Encapsulates state for texture sampling in a state object.
ComparisonFunction comparisonFunction
Specifies the comparison function to use when applying a comparison sampler.
unsigned int maxAnisotropy
Specifies the maximum number of anisotropic samples to use when sampling a texture.
AddressMode addressModeW
Specifies the addressing mode along the W axis in texture coordinate space.
AddressMode addressModeS
Specifies the addressing mode along the S axis in texture coordinate space.
FilterMode filter
Specifies the filter to use for texture sampling.
AddressMode addressModeT
Specifies the addressing mode along the T axis in texture coordinate space.
@ DepthBuffer
The texture can be used as a depth target and have depth buffer values written into.
@ RenderTarget
The texture can be used as a render target and drawn into.
@ Texture
Texture usage, see Default.
Describes how to fetch data from a texture in shaders.
TextureHandle loadTexture(const TextureDescription &desc, const TextureData *data) override
Load a texture from the given description.
void releaseSamplerState(SamplerStateHandle handle) override
Release the sampler state with the given handle.
void releaseTextureView(const TextureViewHandle &handle) override
Release the given texture view.
SamplerStateHandle loadSamplerState(const SamplerState &state) override
Load a sampler state object.
void releaseTexture(TextureHandle textureHandle) override
Release the texture with the given textureHandle.
void releaseResources() override
Release all allocated texture resources.
TextureViewHandle createTextureView(TextureViewDescription &viewDescription) override
Create a texture view used to bind a limited view of the texture data to the rendering pipeline.
void generateMipmaps(TextureHandle textureHandle) override
Use the graphics device to generate mipmaps for the texture with the given texture handle.
void * getNativeHandle(TextureHandle textureHandle) override
Get the device-specific handle (D3D texture pointer, OpenGL texture ID etc) associated with the given...