From 5a824ee0155cfb02e034edf03d723800ec8196eb Mon Sep 17 00:00:00 2001 From: bailwillharr Date: Thu, 23 Mar 2023 19:07:10 +0000 Subject: [PATCH] Finally get textures working again --- include/application.hpp | 24 +++++----- include/gfx.hpp | 1 - include/gfx_device.hpp | 10 ---- include/resources/texture.hpp | 8 ++-- include/util/files.hpp | 3 ++ res/engine/shaders/skybox.frag | 13 ++---- res/engine/shaders/skybox.vert | 22 ++++----- res/engine/shaders/standard.frag | 6 +-- res/engine/shaders/standard.vert | 24 +++++----- src/application.cpp | 78 +++++++++++++++----------------- src/gfx_device_vulkan.cpp | 77 ++++++++++++------------------- src/resources/shader.cpp | 5 +- src/resources/texture.cpp | 24 +++++----- src/systems/render.cpp | 18 +++++--- src/util/files.cpp | 1 - src/util/model_loader.cpp | 2 +- test/src/game.cpp | 26 ++++++----- 17 files changed, 158 insertions(+), 184 deletions(-) diff --git a/include/application.hpp b/include/application.hpp index 07b96d2..a21823a 100644 --- a/include/application.hpp +++ b/include/application.hpp @@ -30,22 +30,24 @@ namespace engine { gfx::DrawBuffer* drawBuffer = nullptr; /* uniforms for engine globals */ - const gfx::DescriptorSetLayout* setZeroLayout; - const gfx::DescriptorSet* setZero; - struct SetZeroBuffer { + const gfx::DescriptorSetLayout* globalSetLayout; + const gfx::DescriptorSet* globalSet; + struct GlobalSetUniformBuffer { glm::mat4 proj; }; - const gfx::Image* myImage = nullptr; - const gfx::Sampler* mySampler = nullptr; - - gfx::UniformBuffer* setZeroBuffer; + gfx::UniformBuffer* globalSetUniformBuffer; + /* uniforms for per-frame data */ - const gfx::DescriptorSetLayout* setOneLayout; - const gfx::DescriptorSet* setOne; - struct SetOneBuffer { + const gfx::DescriptorSetLayout* frameSetLayout; + const gfx::DescriptorSet* frameSet; + struct FrameSetUniformBuffer { glm::mat4 view; }; - gfx::UniformBuffer* setOneBuffer; + gfx::UniformBuffer* frameSetUniformBuffer; + + /* this descriptor set is bound per-material */ + const gfx::DescriptorSetLayout* materialSetLayout; + const gfx::Sampler* materialSetSampler; }; class Application { diff --git a/include/gfx.hpp b/include/gfx.hpp index 38979c3..bbad17c 100644 --- a/include/gfx.hpp +++ b/include/gfx.hpp @@ -12,7 +12,6 @@ namespace engine::gfx { struct Pipeline; struct UniformBuffer; struct Buffer; - struct Texture; struct DrawBuffer; struct DescriptorSetLayout; struct DescriptorSet; diff --git a/include/gfx_device.hpp b/include/gfx_device.hpp index a63344a..c473ba7 100644 --- a/include/gfx_device.hpp +++ b/include/gfx_device.hpp @@ -55,16 +55,6 @@ namespace engine { gfx::Sampler* createSampler(); void destroySampler(const gfx::Sampler* sampler); - gfx::Texture* createTexture( - const void* imageData, - uint32_t width, - uint32_t height, - gfx::TextureFilter minFilter, - gfx::TextureFilter magFilter, - gfx::MipmapSetting mipmapSetting, - bool useAnisotropy = false); - void destroyTexture(const gfx::Texture* texture); - uint64_t getFrameCount(); void logPerformanceInfo(); diff --git a/include/resources/texture.hpp b/include/resources/texture.hpp index 1149264..9f6068d 100644 --- a/include/resources/texture.hpp +++ b/include/resources/texture.hpp @@ -16,16 +16,18 @@ public: ANISOTROPIC, }; - Texture(GFXDevice* gfxDevice, const std::string& path, Filtering filtering, bool useMipmaps, bool useLinearMagFilter); + Texture(GFXDevice* gfxDevice, const gfx::DescriptorSetLayout* materialSetLayout, const gfx::Sampler* sampler, const std::string& path, Filtering filtering, bool useMipmaps, bool useLinearMagFilter); ~Texture(); Texture(const Texture&) = delete; Texture& operator=(const Texture&) = delete; - gfx::Texture* getHandle(); + const gfx::Image* getImage() { return m_image; } + const gfx::DescriptorSet* getDescriptorSet() { return m_descriptorSet; } private: GFXDevice* m_gfxDevice; - gfx::Texture* m_gpuTexture; + const gfx::Image* m_image; + const gfx::DescriptorSet* m_descriptorSet; }; } diff --git a/include/util/files.hpp b/include/util/files.hpp index 4745841..f4d0215 100644 --- a/include/util/files.hpp +++ b/include/util/files.hpp @@ -8,6 +8,9 @@ namespace engine::util { std::unique_ptr> readTextFile(const std::string& path); std::unique_ptr> readBinaryFile(const std::string& path); + + // Read an image file into a vector byte buffer. PNG and JPG support at a minimum. + // Output format is R8G8B8A8_UINT std::unique_ptr> readImageFile(const std::string& path, int *width, int *height); } diff --git a/res/engine/shaders/skybox.frag b/res/engine/shaders/skybox.frag index df34ad9..8e5a402 100644 --- a/res/engine/shaders/skybox.frag +++ b/res/engine/shaders/skybox.frag @@ -1,16 +1,11 @@ #version 450 +layout(set = 2, binding = 0) uniform sampler2D materialSetSampler; + layout(location = 0) in vec2 fragUV; layout(location = 0) out vec4 outColor; -//layout(set = 1, binding = 0) uniform sampler2D texSampler; - void main() { - - gl_FragDepth = 0.9999; - //outColor = texture(texSampler, fragUV); - outColor = vec4(fragUV, 0.0, 1.0); - -} - + outColor = texture(materialSetSampler, fragUV); +} \ No newline at end of file diff --git a/res/engine/shaders/skybox.vert b/res/engine/shaders/skybox.vert index 53870c4..c7e94c3 100644 --- a/res/engine/shaders/skybox.vert +++ b/res/engine/shaders/skybox.vert @@ -1,26 +1,24 @@ #version 450 +layout(set = 0, binding = 0) uniform GlobalSetUniformBuffer { + mat4 proj; +} globalSetUniformBuffer; + +layout(set = 1, binding = 0) uniform FrameSetUniformBuffer { + mat4 view; +} frameSetUniformBuffer; + layout( push_constant ) uniform Constants { mat4 model; } constants; -layout(set = 0, binding = 0) uniform SetZeroBuffer { - mat4 proj; -} setZeroBuffer; - -layout(set = 1, binding = 0) uniform SetOneBuffer { - mat4 view; -} setOneBuffer; - layout(location = 0) in vec3 inPosition; layout(location = 2) in vec2 inUV; layout(location = 0) out vec2 fragUV; void main() { - mat4 myView = setOneBuffer.view; - myView[3] = vec4(0.0, 0.0, 0.0, 1.0); - vec4 pos = setZeroBuffer.proj * myView * constants.model * vec4(inPosition, 1.0); - gl_Position = pos; + vec3 position = mat3(frameSetUniformBuffer.view) * vec3(constants.model * vec4(inPosition, 1.0)); + gl_Position = (globalSetUniformBuffer.proj * vec4(position, 0.0)).xyzz; fragUV = inUV; } diff --git a/res/engine/shaders/standard.frag b/res/engine/shaders/standard.frag index df6d444..c750561 100644 --- a/res/engine/shaders/standard.frag +++ b/res/engine/shaders/standard.frag @@ -1,5 +1,7 @@ #version 450 +layout(set = 2, binding = 0) uniform sampler2D materialSetSampler; + layout(location = 0) in vec3 fragPos; layout(location = 1) in vec3 fragNorm; layout(location = 2) in vec2 fragUV; @@ -7,15 +9,13 @@ layout(location = 3) in vec3 fragLightPos; layout(location = 0) out vec4 outColor; -layout(set = 0, binding = 1) uniform sampler2D texSampler; - void main() { // constants vec3 lightColor = vec3(1.0, 1.0, 1.0); vec3 ambientColor = vec3(1.0, 1.0, 1.0); float ambientStrength = 0.05; - vec3 baseColor = vec3(texture(texSampler, fragUV)); + vec3 baseColor = vec3(texture(materialSetSampler, fragUV)); vec3 emission = vec3(0.0, 0.0, 0.0); // code diff --git a/res/engine/shaders/standard.vert b/res/engine/shaders/standard.vert index 6eedeb6..110f309 100644 --- a/res/engine/shaders/standard.vert +++ b/res/engine/shaders/standard.vert @@ -1,17 +1,17 @@ #version 450 +layout(set = 0, binding = 0) uniform GlobalSetUniformBuffer { + mat4 proj; +} globalSetUniformBuffer; + +layout(set = 1, binding = 0) uniform FrameSetUniformBuffer { + mat4 view; +} frameSetUniformBuffer; + layout( push_constant ) uniform Constants { mat4 model; } constants; -layout(set = 0, binding = 0) uniform SetZeroBuffer { - mat4 proj; -} setZeroBuffer; - -layout(set = 1, binding = 0) uniform SetOneBuffer { - mat4 view; -} setOneBuffer; - layout(location = 0) in vec3 inPosition; layout(location = 1) in vec3 inNorm; layout(location = 2) in vec2 inUV; @@ -22,12 +22,12 @@ layout(location = 2) out vec2 fragUV; layout(location = 3) out vec3 fragLightPos; void main() { - gl_Position = setZeroBuffer.proj * setOneBuffer.view * constants.model * vec4(inPosition, 1.0); + gl_Position = globalSetUniformBuffer.proj * frameSetUniformBuffer.view * constants.model * vec4(inPosition, 1.0); - fragPos = vec3(setOneBuffer.view * constants.model * vec4(inPosition, 1.0)); - fragNorm = mat3(transpose(inverse(setOneBuffer.view * constants.model))) * inNorm; + fragPos = vec3(frameSetUniformBuffer.view * constants.model * vec4(inPosition, 1.0)); + fragNorm = mat3(transpose(inverse(frameSetUniformBuffer.view * constants.model))) * inNorm; fragUV = inUV; vec3 lightPos = vec3(2000.0, 2000.0, -2000.0); - fragLightPos = vec3(setOneBuffer.view * vec4(lightPos, 1.0)); + fragLightPos = vec3(frameSetUniformBuffer.view * vec4(lightPos, 1.0)); } diff --git a/src/application.cpp b/src/application.cpp index f1746f7..cd23814 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -14,7 +14,7 @@ #include "resources/shader.hpp" #include "resources/texture.hpp" -#include +#include // To allow the FPS-limiter to put the thread to sleep #include @@ -76,49 +76,42 @@ namespace engine { // initialise the render data renderData.gfxdev = std::make_unique(appName, appVersion, m_window->getHandle(), graphicsSettings); - std::vector setZeroLayoutBindings; + std::vector globalSetBindings; { - auto& binding0 = setZeroLayoutBindings.emplace_back(); + auto& binding0 = globalSetBindings.emplace_back(); binding0.descriptorType = gfx::DescriptorType::UNIFORM_BUFFER; binding0.stageFlags = gfx::ShaderStageFlags::VERTEX; - auto& binding1 = setZeroLayoutBindings.emplace_back(); - binding1.descriptorType = gfx::DescriptorType::COMBINED_IMAGE_SAMPLER; - binding1.stageFlags = gfx::ShaderStageFlags::FRAGMENT; } - renderData.setZeroLayout = gfx()->createDescriptorSetLayout(setZeroLayoutBindings); - renderData.setZero = gfx()->allocateDescriptorSet(renderData.setZeroLayout); - RenderData::SetZeroBuffer initialSetZeroData{ - .proj = glm::perspectiveZO(glm::radians(70.0f), 1024.0f / 768.0f, 0.1f, 1000.0f), + renderData.globalSetLayout = gfx()->createDescriptorSetLayout(globalSetBindings); + renderData.globalSet = gfx()->allocateDescriptorSet(renderData.globalSetLayout); + RenderData::GlobalSetUniformBuffer globalSetUniformBufferData{ + .proj = glm::mat4{ 1.0f }, }; - renderData.setZeroBuffer = gfx()->createUniformBuffer(sizeof(RenderData::SetZeroBuffer), &initialSetZeroData); - gfx()->updateDescriptorUniformBuffer(renderData.setZero, 0, renderData.setZeroBuffer, 0, sizeof(RenderData::SetZeroBuffer)); + renderData.globalSetUniformBuffer = gfx()->createUniformBuffer(sizeof(RenderData::GlobalSetUniformBuffer), &globalSetUniformBufferData); + gfx()->updateDescriptorUniformBuffer(renderData.globalSet, 0, renderData.globalSetUniformBuffer, 0, sizeof(RenderData::GlobalSetUniformBuffer)); - uint8_t* imageData = new uint8_t[16*16*4]; - for (int i = 0; i < 16*16*4; i += 4) { - imageData[i + 0] = ((i / 4u) % 16u) * 16u; - imageData[i + 1] = (i / 4u) & 0xF0u; - imageData[i + 2] = 0x00; - imageData[i + 3] = 0xFF; - } - renderData.myImage = gfx()->createImage(16, 16, imageData); - delete[] imageData; - - renderData.mySampler = gfx()->createSampler(); - gfx()->updateDescriptorCombinedImageSampler(renderData.setZero, 1, renderData.myImage, renderData.mySampler); - - std::vector setOneLayoutBindings; + std::vector frameSetBindings; { - auto& binding0 = setOneLayoutBindings.emplace_back(); + auto& binding0 = frameSetBindings.emplace_back(); binding0.descriptorType = gfx::DescriptorType::UNIFORM_BUFFER; binding0.stageFlags = gfx::ShaderStageFlags::VERTEX; } - renderData.setOneLayout = gfx()->createDescriptorSetLayout(setOneLayoutBindings); - renderData.setOne = gfx()->allocateDescriptorSet(renderData.setOneLayout); - RenderData::SetOneBuffer initialSetOneData{ + renderData.frameSetLayout = gfx()->createDescriptorSetLayout(frameSetBindings); + renderData.frameSet = gfx()->allocateDescriptorSet(renderData.frameSetLayout); + RenderData::FrameSetUniformBuffer initialSetOneData{ .view = glm::mat4{ 1.0f }, }; - renderData.setOneBuffer = gfx()->createUniformBuffer(sizeof(RenderData::SetOneBuffer), &initialSetOneData); - gfx()->updateDescriptorUniformBuffer(renderData.setOne, 0, renderData.setOneBuffer, 0, sizeof(RenderData::SetOneBuffer)); + renderData.frameSetUniformBuffer = gfx()->createUniformBuffer(sizeof(RenderData::FrameSetUniformBuffer), &initialSetOneData); + gfx()->updateDescriptorUniformBuffer(renderData.frameSet, 0, renderData.frameSetUniformBuffer, 0, sizeof(RenderData::FrameSetUniformBuffer)); + + std::vector materialSetBindings; + { + auto& binding0 = materialSetBindings.emplace_back(); + binding0.descriptorType = gfx::DescriptorType::COMBINED_IMAGE_SAMPLER; + binding0.stageFlags = gfx::ShaderStageFlags::FRAGMENT; + } + renderData.materialSetLayout = gfx()->createDescriptorSetLayout(materialSetBindings); + renderData.materialSetSampler = gfx()->createSampler(); // default resources { @@ -135,11 +128,11 @@ namespace engine { ); getResourceManager()->addPersistent("builtin.standard", std::move(texturedShader)); } - if (0) { + { resources::Shader::VertexParams vertParams{}; vertParams.hasNormal = true; vertParams.hasUV0 = true; - auto texturedShader = std::make_unique( + auto skyboxShader = std::make_unique( &renderData, getResourcePath("engine/shaders/skybox.vert").c_str(), getResourcePath("engine/shaders/skybox.frag").c_str(), @@ -147,11 +140,13 @@ namespace engine { false, true ); - getResourceManager()->addPersistent("builtin.skybox", std::move(texturedShader)); + getResourceManager()->addPersistent("builtin.skybox", std::move(skyboxShader)); } { auto whiteTexture = std::make_unique( gfx(), + renderData.materialSetLayout, + renderData.materialSetSampler, getResourcePath("engine/textures/white.png"), resources::Texture::Filtering::OFF, false, @@ -163,13 +158,14 @@ namespace engine { Application::~Application() { - gfx()->destroyUniformBuffer(renderData.setOneBuffer); - gfx()->destroyDescriptorSetLayout(renderData.setOneLayout); + gfx()->destroySampler(renderData.materialSetSampler); + gfx()->destroyDescriptorSetLayout(renderData.materialSetLayout); - gfx()->destroySampler(renderData.mySampler); - gfx()->destroyImage(renderData.myImage); - gfx()->destroyUniformBuffer(renderData.setZeroBuffer); - gfx()->destroyDescriptorSetLayout(renderData.setZeroLayout); + gfx()->destroyUniformBuffer(renderData.frameSetUniformBuffer); + gfx()->destroyDescriptorSetLayout(renderData.frameSetLayout); + + gfx()->destroyUniformBuffer(renderData.globalSetUniformBuffer); + gfx()->destroyDescriptorSetLayout(renderData.globalSetLayout); } void Application::gameLoop() diff --git a/src/gfx_device_vulkan.cpp b/src/gfx_device_vulkan.cpp index 600b9c4..01d06f0 100644 --- a/src/gfx_device_vulkan.cpp +++ b/src/gfx_device_vulkan.cpp @@ -104,10 +104,6 @@ namespace engine { VkSampler sampler = VK_NULL_HANDLE; }; - struct gfx::Texture { - - }; - struct gfx::DrawBuffer { FrameData frameData{}; uint32_t currentFrameIndex = 0; // corresponds to the frameData @@ -322,7 +318,10 @@ namespace engine { VkDescriptorPool descriptorPool; std::array, FRAMES_IN_FLIGHT> uniformBufferWriteQueues{}; + // For one-off transfer operations not bound to a specific frame-in-flight VkCommandPool transferCommandPool = VK_NULL_HANDLE; + // For one-off operation on the draw queue family not bound to a specific frame-in-flight + VkCommandPool graphicsCommandPool = VK_NULL_HANDLE; uint64_t FRAMECOUNT = 0; @@ -483,16 +482,25 @@ namespace engine { .queueFamilyIndex = pimpl->device.queues.transferQueueFamily }; VKCHECK(vkCreateCommandPool(pimpl->device.device, &transferPoolInfo, nullptr, &pimpl->transferCommandPool)); + /* create command pool for one-off draw queue operations */ + VkCommandPoolCreateInfo graphicsPoolInfo{ + .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + .pNext = nullptr, + .flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, // These command buffers don't last very long + .queueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily + }; + VKCHECK(vkCreateCommandPool(pimpl->device.device, &graphicsPoolInfo, nullptr, &pimpl->graphicsCommandPool)); /* create a global descriptor pool */ std::vector poolSizes{}; - poolSizes.push_back({ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 100u }); // purposely low limit + poolSizes.push_back({ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 100u }); + poolSizes.push_back({ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 100u }); VkDescriptorPoolCreateInfo descriptorPoolInfo{}; descriptorPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; descriptorPoolInfo.pNext = nullptr; descriptorPoolInfo.flags = 0; - descriptorPoolInfo.maxSets = 100; // purposely low limit + descriptorPoolInfo.maxSets = 1000u; descriptorPoolInfo.poolSizeCount = (uint32_t)poolSizes.size(); descriptorPoolInfo.pPoolSizes = poolSizes.data(); VKCHECK(vkCreateDescriptorPool(pimpl->device.device, &descriptorPoolInfo, nullptr, &pimpl->descriptorPool)); @@ -503,6 +511,7 @@ namespace engine { { vkDestroyDescriptorPool(pimpl->device.device, pimpl->descriptorPool, nullptr); + vkDestroyCommandPool(pimpl->device.device, pimpl->graphicsCommandPool, nullptr); vkDestroyCommandPool(pimpl->device.device, pimpl->transferCommandPool, nullptr); for (uint32_t i = 0; i < FRAMES_IN_FLIGHT; i++) { @@ -535,8 +544,6 @@ namespace engine { } } - /* TODO: the descriptor buffer copy command buffers are never freed. - * This causes the program to crash on IGPU after around 1 minute. (VK_ERROR_DEVICE_LOST on a vkQueueSubmit) */ gfx::DrawBuffer* GFXDevice::beginRender() { VkResult res; @@ -951,7 +958,7 @@ namespace engine { depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; depthStencil.depthTestEnable = VK_TRUE; depthStencil.depthWriteEnable = VK_TRUE; - depthStencil.depthCompareOp = VK_COMPARE_OP_LESS; + depthStencil.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; depthStencil.depthBoundsTestEnable = VK_FALSE; depthStencil.minDepthBounds = 0.0f; depthStencil.maxDepthBounds = 1.0f; @@ -1315,7 +1322,7 @@ namespace engine { imageInfo.arrayLayers = 1; imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT; + imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; @@ -1343,7 +1350,7 @@ namespace engine { VkCommandBufferAllocateInfo allocInfo{}; allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - allocInfo.commandPool = pimpl->transferCommandPool; + allocInfo.commandPool = pimpl->graphicsCommandPool; allocInfo.commandBufferCount = 1; VkCommandBuffer commandBuffer; @@ -1363,8 +1370,8 @@ namespace engine { barrier.dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT; barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - barrier.srcQueueFamilyIndex = pimpl->device.queues.transferQueueFamily; - barrier.dstQueueFamilyIndex = pimpl->device.queues.transferQueueFamily; + barrier.srcQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily; + barrier.dstQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily; barrier.image = out->image; barrier.subresourceRange = viewInfo.subresourceRange; @@ -1397,7 +1404,7 @@ namespace engine { barrier.dstAccessMask = VK_ACCESS_2_SHADER_SAMPLED_READ_BIT; barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - barrier.srcQueueFamilyIndex = pimpl->device.queues.transferQueueFamily; + barrier.srcQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily; barrier.dstQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily; vkCmdPipelineBarrier2(commandBuffer, &depInfo); @@ -1411,11 +1418,11 @@ namespace engine { submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &commandBuffer; - VKCHECK(vkQueueSubmit(pimpl->device.queues.transferQueues[0], 1, &submitInfo, VK_NULL_HANDLE)); + VKCHECK(vkQueueSubmit(pimpl->device.queues.drawQueues[0], 1, &submitInfo, VK_NULL_HANDLE)); - VKCHECK(vkQueueWaitIdle(pimpl->device.queues.transferQueues[0])); + VKCHECK(vkQueueWaitIdle(pimpl->device.queues.drawQueues[0])); - vkFreeCommandBuffers(pimpl->device.device, pimpl->transferCommandPool, 1, &commandBuffer); + vkFreeCommandBuffers(pimpl->device.device, pimpl->graphicsCommandPool, 1, &commandBuffer); vmaDestroyBuffer(pimpl->allocator, stagingBuffer, stagingAllocation); @@ -1436,15 +1443,15 @@ namespace engine { VkSamplerCreateInfo samplerInfo{}; samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; samplerInfo.magFilter = VK_FILTER_NEAREST; - samplerInfo.minFilter = VK_FILTER_NEAREST; - samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; + samplerInfo.minFilter = VK_FILTER_LINEAR; + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; - samplerInfo.mipLodBias = 0.0f; // wtf + samplerInfo.mipLodBias = 0.0f; samplerInfo.anisotropyEnable = VK_FALSE; samplerInfo.minLod = 0.0f; - samplerInfo.maxLod = 0.0f; + samplerInfo.maxLod = VK_LOD_CLAMP_NONE; VKCHECK(vkCreateSampler(pimpl->device.device, &samplerInfo, nullptr, &out->sampler)); @@ -1457,32 +1464,6 @@ namespace engine { delete sampler; } - gfx::Texture* GFXDevice::createTexture( - const void* imageData, - uint32_t width, - uint32_t height, - gfx::TextureFilter minFilter, - gfx::TextureFilter magFilter, - gfx::MipmapSetting mipmapSetting, - bool useAnisotropy) - { - (void)imageData; - (void)width; - (void)height; - (void)minFilter; - (void)magFilter; - (void)mipmapSetting; - (void)useAnisotropy; - auto out = new gfx::Texture; - - return out; - } - - void GFXDevice::destroyTexture(const gfx::Texture* texture) - { - (void)texture; - } - void GFXDevice::logPerformanceInfo() { VmaTotalStatistics pStats{}; @@ -1517,4 +1498,4 @@ namespace engine { vkDeviceWaitIdle(pimpl->device.device); } -} \ No newline at end of file +} diff --git a/src/resources/shader.cpp b/src/resources/shader.cpp index 6bcccc5..daeeefa 100644 --- a/src/resources/shader.cpp +++ b/src/resources/shader.cpp @@ -44,8 +44,9 @@ namespace engine::resources { info.vertexFormat = vertFormat; info.alphaBlending = alphaBlending; info.backfaceCulling = cullBackFace; - info.descriptorSetLayouts.push_back(renderData->setZeroLayout); - info.descriptorSetLayouts.push_back(renderData->setOneLayout); + info.descriptorSetLayouts.push_back(renderData->globalSetLayout); + info.descriptorSetLayouts.push_back(renderData->frameSetLayout); + info.descriptorSetLayouts.push_back(renderData->materialSetLayout); m_pipeline = m_gfx->createPipeline(info); diff --git a/src/resources/texture.cpp b/src/resources/texture.cpp index 0d428ce..68b6800 100644 --- a/src/resources/texture.cpp +++ b/src/resources/texture.cpp @@ -7,12 +7,12 @@ namespace engine::resources { -Texture::Texture(GFXDevice* gfxDevice, const std::string& path, Filtering filtering, bool useMipmaps, bool useLinearMagFilter) +Texture::Texture(GFXDevice* gfxDevice, const gfx::DescriptorSetLayout* materialSetLayout, const gfx::Sampler* sampler, const std::string& path, Filtering filtering, bool useMipmaps, bool useLinearMagFilter) : m_gfxDevice(gfxDevice) { int width, height; - auto texbuf = util::readImageFile(path, &width, &height); + std::unique_ptr> texbuf = util::readImageFile(path, &width, &height); gfx::TextureFilter minFilter = gfx::TextureFilter::NEAREST; gfx::TextureFilter magFilter = gfx::TextureFilter::NEAREST; @@ -51,11 +51,14 @@ Texture::Texture(GFXDevice* gfxDevice, const std::string& path, Filtering filter mipmapSetting = gfx::MipmapSetting::OFF; } - m_gpuTexture = m_gfxDevice->createTexture( - texbuf->data(), (uint32_t)width, (uint32_t)height, - minFilter, magFilter, - mipmapSetting, - anisotropyEnable); + (void)minFilter; + (void)magFilter; + (void)mipmapSetting; + (void)anisotropyEnable; + + m_image = m_gfxDevice->createImage(width, height, texbuf->data()); + m_descriptorSet = m_gfxDevice->allocateDescriptorSet(materialSetLayout); + m_gfxDevice->updateDescriptorCombinedImageSampler(m_descriptorSet, 0, m_image, sampler); LOG_INFO("Loaded texture: {}, width: {} height: {}", path, width, height); @@ -63,12 +66,7 @@ Texture::Texture(GFXDevice* gfxDevice, const std::string& path, Filtering filter Texture::~Texture() { - m_gfxDevice->destroyTexture(m_gpuTexture); -} - -gfx::Texture* Texture::getHandle() -{ - return m_gpuTexture; + m_gfxDevice->destroyImage(m_image); } } diff --git a/src/systems/render.cpp b/src/systems/render.cpp index dc10c14..2733ba6 100644 --- a/src/systems/render.cpp +++ b/src/systems/render.cpp @@ -45,16 +45,16 @@ namespace engine { const float verticalFovRadians = glm::radians(m_camera.verticalFovDegrees); const glm::mat4 projMatrix = glm::perspectiveZO(verticalFovRadians, m_viewportAspectRatio, m_camera.clipNear, m_camera.clipFar); /* update SET 0 */ - RenderData::SetZeroBuffer setZeroBuffer{ + RenderData::GlobalSetUniformBuffer globalSetUniformBuffer{ .proj = projMatrix }; - m_gfx->writeUniformBuffer(renderData.setZeroBuffer, 0, sizeof(RenderData::SetZeroBuffer), &setZeroBuffer); + m_gfx->writeUniformBuffer(renderData.globalSetUniformBuffer, 0, sizeof(RenderData::GlobalSetUniformBuffer), &globalSetUniformBuffer); } - RenderData::SetOneBuffer setOneBuffer{ + RenderData::FrameSetUniformBuffer frameSetUniformBuffer{ .view = viewMatrix }; - m_gfx->writeUniformBuffer(renderData.setOneBuffer, 0, sizeof(RenderData::SetOneBuffer), &setOneBuffer); + m_gfx->writeUniformBuffer(renderData.frameSetUniformBuffer, 0, sizeof(RenderData::FrameSetUniformBuffer), &frameSetUniformBuffer); /* render all renderable entities */ @@ -65,6 +65,7 @@ namespace engine { struct DrawCallData { const gfx::Buffer* vb; const gfx::Buffer* ib; + const gfx::DescriptorSet* materialSet; uint32_t indexCount; PushConstants pushConsts; }; @@ -75,6 +76,7 @@ namespace engine { auto r = m_scene->getComponent(entity); assert(r != nullptr); assert(r->material != nullptr); + assert(r->material->m_texture != nullptr); assert(r->mesh != nullptr); if (r->shown == false) continue; @@ -85,6 +87,7 @@ namespace engine { DrawCallData data{}; data.vb = r->mesh->getVB(); data.ib = r->mesh->getIB(); + data.materialSet = r->material->m_texture->getDescriptorSet(); data.indexCount = r->mesh->getCount(); data.pushConsts.model = t->worldMatrix; @@ -97,12 +100,15 @@ namespace engine { /* these descriptor set bindings should persist across pipeline changes */ const gfx::Pipeline* firstPipeline = pipelineDrawCalls.begin()->first; - m_gfx->cmdBindDescriptorSet(renderData.drawBuffer, firstPipeline, renderData.setZero, 0); - m_gfx->cmdBindDescriptorSet(renderData.drawBuffer, firstPipeline, renderData.setOne, 1); + m_gfx->cmdBindDescriptorSet(renderData.drawBuffer, firstPipeline, renderData.globalSet, 0); + m_gfx->cmdBindDescriptorSet(renderData.drawBuffer, firstPipeline, renderData.frameSet, 1); for (const auto& [pipeline, drawCalls] : pipelineDrawCalls) { m_gfx->cmdBindPipeline(renderData.drawBuffer, pipeline); for (const auto& drawCall : drawCalls) { + m_gfx->cmdBindDescriptorSet(renderData.drawBuffer, pipeline, renderData.globalSet, 0); + m_gfx->cmdBindDescriptorSet(renderData.drawBuffer, pipeline, renderData.frameSet, 1); + m_gfx->cmdBindDescriptorSet(renderData.drawBuffer, pipeline, drawCall.materialSet, 2); m_gfx->cmdPushConstants(renderData.drawBuffer, pipeline, 0, sizeof(PushConstants), &drawCall.pushConsts); m_gfx->cmdBindVertexBuffer(renderData.drawBuffer, 0, drawCall.vb); m_gfx->cmdBindIndexBuffer(renderData.drawBuffer, drawCall.ib); diff --git a/src/util/files.cpp b/src/util/files.cpp index 9254560..422666e 100644 --- a/src/util/files.cpp +++ b/src/util/files.cpp @@ -51,7 +51,6 @@ namespace engine::util { return buffer; } - // Read an image file into a vector byte buffer. PNG and JPG support at a minimum std::unique_ptr> readImageFile(const std::string& path, int *width, int *height) { int x, y, n; diff --git a/src/util/model_loader.cpp b/src/util/model_loader.cpp index 3cde87a..2a2d2b8 100644 --- a/src/util/model_loader.cpp +++ b/src/util/model_loader.cpp @@ -182,7 +182,7 @@ namespace engine::util { absPath /= texPath.C_Str(); try { textures[i] = std::make_shared( - parent->app()->gfx(), absPath.string(), + parent->app()->gfx(), parent->app()->renderData.materialSetLayout, parent->app()->renderData.materialSetSampler, absPath.string(), resources::Texture::Filtering::TRILINEAR, true, true); } catch (const std::runtime_error&) { textures[i] = parent->app()->getResource("builtin.white"); diff --git a/test/src/game.cpp b/test/src/game.cpp index 1364b45..25cdd7a 100644 --- a/test/src/game.cpp +++ b/test/src/game.cpp @@ -85,6 +85,8 @@ void playGame(GameSettings settings) /* shared resources */ auto grassTexture = std::make_shared( app.gfx(), + app.renderData.materialSetLayout, + app.renderData.materialSetSampler, app.getResourcePath("textures/grass.jpg"), engine::resources::Texture::Filtering::ANISOTROPIC, true, @@ -92,29 +94,21 @@ void playGame(GameSettings settings) ); auto spaceTexture = std::make_shared( app.gfx(), + app.renderData.materialSetLayout, + app.renderData.materialSetSampler, app.getResourcePath("textures/space2.png"), engine::resources::Texture::Filtering::ANISOTROPIC, true, true ); - /* skybox */ - if (0) { - uint32_t skybox = myScene->createEntity("skybox"); - auto skyboxRenderable = myScene->addComponent(skybox); - skyboxRenderable->material = std::make_unique(app.getResource("builtin.skybox")); - skyboxRenderable->material->m_texture = spaceTexture; -// skyboxRenderable->mesh = genSphereMesh(app.gfx(), 1.0f, 50, true); - skyboxRenderable->mesh = genCuboidMesh(app.gfx(), 10.0f, 10.0f, 10.0f, 1.0f, true); - myScene->getComponent(skybox)->position = { -5.0f, -5.0f, -5.0f }; - } - /* cube */ { uint32_t cube = myScene->createEntity("cube"); myScene->getComponent(cube)->position = glm::vec3{ -0.5f + 5.0f, -0.5f + 5.0f, -0.5f + 5.0f }; auto cubeRenderable = myScene->addComponent(cube); cubeRenderable->material = std::make_shared(app.getResource("builtin.standard")); + cubeRenderable->material->m_texture = app.getResource("builtin.white"); cubeRenderable->mesh = genCuboidMesh(app.gfx(), 1.0f, 1.0f, 1.0f, 1); auto cubeCollider = myScene->addComponent(cube); cubeCollider->isStatic = true; @@ -137,6 +131,16 @@ void playGame(GameSettings settings) //engine::util::loadMeshFromFile(myScene, app.getResourcePath("models/astronaut/astronaut.dae")); + /* skybox */ + { + uint32_t skybox = myScene->createEntity("skybox"); + auto skyboxRenderable = myScene->addComponent(skybox); + skyboxRenderable->material = std::make_unique(app.getResource("builtin.skybox")); + skyboxRenderable->material->m_texture = spaceTexture; + skyboxRenderable->mesh = genCuboidMesh(app.gfx(), 10.0f, 10.0f, 10.0f, 1.0f, true); + myScene->getComponent(skybox)->position = { -5.0f, -5.0f, -5.0f }; + } + app.gameLoop(); }