Finally get textures working again

This commit is contained in:
Bailey Harrison 2023-03-23 19:07:10 +00:00
parent 8f596c9e15
commit 5a824ee015
17 changed files with 158 additions and 184 deletions

View File

@ -30,22 +30,24 @@ namespace engine {
gfx::DrawBuffer* drawBuffer = nullptr; gfx::DrawBuffer* drawBuffer = nullptr;
/* uniforms for engine globals */ /* uniforms for engine globals */
const gfx::DescriptorSetLayout* setZeroLayout; const gfx::DescriptorSetLayout* globalSetLayout;
const gfx::DescriptorSet* setZero; const gfx::DescriptorSet* globalSet;
struct SetZeroBuffer { struct GlobalSetUniformBuffer {
glm::mat4 proj; glm::mat4 proj;
}; };
const gfx::Image* myImage = nullptr; gfx::UniformBuffer* globalSetUniformBuffer;
const gfx::Sampler* mySampler = nullptr;
gfx::UniformBuffer* setZeroBuffer;
/* uniforms for per-frame data */ /* uniforms for per-frame data */
const gfx::DescriptorSetLayout* setOneLayout; const gfx::DescriptorSetLayout* frameSetLayout;
const gfx::DescriptorSet* setOne; const gfx::DescriptorSet* frameSet;
struct SetOneBuffer { struct FrameSetUniformBuffer {
glm::mat4 view; 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 { class Application {

View File

@ -12,7 +12,6 @@ namespace engine::gfx {
struct Pipeline; struct Pipeline;
struct UniformBuffer; struct UniformBuffer;
struct Buffer; struct Buffer;
struct Texture;
struct DrawBuffer; struct DrawBuffer;
struct DescriptorSetLayout; struct DescriptorSetLayout;
struct DescriptorSet; struct DescriptorSet;

View File

@ -55,16 +55,6 @@ namespace engine {
gfx::Sampler* createSampler(); gfx::Sampler* createSampler();
void destroySampler(const gfx::Sampler* sampler); 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(); uint64_t getFrameCount();
void logPerformanceInfo(); void logPerformanceInfo();

View File

@ -16,16 +16,18 @@ public:
ANISOTROPIC, 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();
Texture(const Texture&) = delete; Texture(const Texture&) = delete;
Texture& operator=(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: private:
GFXDevice* m_gfxDevice; GFXDevice* m_gfxDevice;
gfx::Texture* m_gpuTexture; const gfx::Image* m_image;
const gfx::DescriptorSet* m_descriptorSet;
}; };
} }

View File

@ -8,6 +8,9 @@ namespace engine::util {
std::unique_ptr<std::vector<char>> readTextFile(const std::string& path); std::unique_ptr<std::vector<char>> readTextFile(const std::string& path);
std::unique_ptr<std::vector<uint8_t>> readBinaryFile(const std::string& path); std::unique_ptr<std::vector<uint8_t>> 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<std::vector<uint8_t>> readImageFile(const std::string& path, int *width, int *height); std::unique_ptr<std::vector<uint8_t>> readImageFile(const std::string& path, int *width, int *height);
} }

View File

@ -1,16 +1,11 @@
#version 450 #version 450
layout(set = 2, binding = 0) uniform sampler2D materialSetSampler;
layout(location = 0) in vec2 fragUV; layout(location = 0) in vec2 fragUV;
layout(location = 0) out vec4 outColor; layout(location = 0) out vec4 outColor;
//layout(set = 1, binding = 0) uniform sampler2D texSampler;
void main() { void main() {
outColor = texture(materialSetSampler, fragUV);
gl_FragDepth = 0.9999; }
//outColor = texture(texSampler, fragUV);
outColor = vec4(fragUV, 0.0, 1.0);
}

View File

@ -1,26 +1,24 @@
#version 450 #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 { layout( push_constant ) uniform Constants {
mat4 model; mat4 model;
} constants; } 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 = 0) in vec3 inPosition;
layout(location = 2) in vec2 inUV; layout(location = 2) in vec2 inUV;
layout(location = 0) out vec2 fragUV; layout(location = 0) out vec2 fragUV;
void main() { void main() {
mat4 myView = setOneBuffer.view; vec3 position = mat3(frameSetUniformBuffer.view) * vec3(constants.model * vec4(inPosition, 1.0));
myView[3] = vec4(0.0, 0.0, 0.0, 1.0); gl_Position = (globalSetUniformBuffer.proj * vec4(position, 0.0)).xyzz;
vec4 pos = setZeroBuffer.proj * myView * constants.model * vec4(inPosition, 1.0);
gl_Position = pos;
fragUV = inUV; fragUV = inUV;
} }

View File

@ -1,5 +1,7 @@
#version 450 #version 450
layout(set = 2, binding = 0) uniform sampler2D materialSetSampler;
layout(location = 0) in vec3 fragPos; layout(location = 0) in vec3 fragPos;
layout(location = 1) in vec3 fragNorm; layout(location = 1) in vec3 fragNorm;
layout(location = 2) in vec2 fragUV; layout(location = 2) in vec2 fragUV;
@ -7,15 +9,13 @@ layout(location = 3) in vec3 fragLightPos;
layout(location = 0) out vec4 outColor; layout(location = 0) out vec4 outColor;
layout(set = 0, binding = 1) uniform sampler2D texSampler;
void main() { void main() {
// constants // constants
vec3 lightColor = vec3(1.0, 1.0, 1.0); vec3 lightColor = vec3(1.0, 1.0, 1.0);
vec3 ambientColor = vec3(1.0, 1.0, 1.0); vec3 ambientColor = vec3(1.0, 1.0, 1.0);
float ambientStrength = 0.05; 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); vec3 emission = vec3(0.0, 0.0, 0.0);
// code // code

View File

@ -1,17 +1,17 @@
#version 450 #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 { layout( push_constant ) uniform Constants {
mat4 model; mat4 model;
} constants; } 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 = 0) in vec3 inPosition;
layout(location = 1) in vec3 inNorm; layout(location = 1) in vec3 inNorm;
layout(location = 2) in vec2 inUV; layout(location = 2) in vec2 inUV;
@ -22,12 +22,12 @@ layout(location = 2) out vec2 fragUV;
layout(location = 3) out vec3 fragLightPos; layout(location = 3) out vec3 fragLightPos;
void main() { 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)); fragPos = vec3(frameSetUniformBuffer.view * constants.model * vec4(inPosition, 1.0));
fragNorm = mat3(transpose(inverse(setOneBuffer.view * constants.model))) * inNorm; fragNorm = mat3(transpose(inverse(frameSetUniformBuffer.view * constants.model))) * inNorm;
fragUV = inUV; fragUV = inUV;
vec3 lightPos = vec3(2000.0, 2000.0, -2000.0); 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));
} }

View File

@ -14,7 +14,7 @@
#include "resources/shader.hpp" #include "resources/shader.hpp"
#include "resources/texture.hpp" #include "resources/texture.hpp"
#include <glm/gtc/matrix_transform.hpp> #include <glm/mat4x4.hpp>
// To allow the FPS-limiter to put the thread to sleep // To allow the FPS-limiter to put the thread to sleep
#include <thread> #include <thread>
@ -76,49 +76,42 @@ namespace engine {
// initialise the render data // initialise the render data
renderData.gfxdev = std::make_unique<GFXDevice>(appName, appVersion, m_window->getHandle(), graphicsSettings); renderData.gfxdev = std::make_unique<GFXDevice>(appName, appVersion, m_window->getHandle(), graphicsSettings);
std::vector<gfx::DescriptorSetLayoutBinding> setZeroLayoutBindings; std::vector<gfx::DescriptorSetLayoutBinding> globalSetBindings;
{ {
auto& binding0 = setZeroLayoutBindings.emplace_back(); auto& binding0 = globalSetBindings.emplace_back();
binding0.descriptorType = gfx::DescriptorType::UNIFORM_BUFFER; binding0.descriptorType = gfx::DescriptorType::UNIFORM_BUFFER;
binding0.stageFlags = gfx::ShaderStageFlags::VERTEX; 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.globalSetLayout = gfx()->createDescriptorSetLayout(globalSetBindings);
renderData.setZero = gfx()->allocateDescriptorSet(renderData.setZeroLayout); renderData.globalSet = gfx()->allocateDescriptorSet(renderData.globalSetLayout);
RenderData::SetZeroBuffer initialSetZeroData{ RenderData::GlobalSetUniformBuffer globalSetUniformBufferData{
.proj = glm::perspectiveZO(glm::radians(70.0f), 1024.0f / 768.0f, 0.1f, 1000.0f), .proj = glm::mat4{ 1.0f },
}; };
renderData.setZeroBuffer = gfx()->createUniformBuffer(sizeof(RenderData::SetZeroBuffer), &initialSetZeroData); renderData.globalSetUniformBuffer = gfx()->createUniformBuffer(sizeof(RenderData::GlobalSetUniformBuffer), &globalSetUniformBufferData);
gfx()->updateDescriptorUniformBuffer(renderData.setZero, 0, renderData.setZeroBuffer, 0, sizeof(RenderData::SetZeroBuffer)); gfx()->updateDescriptorUniformBuffer(renderData.globalSet, 0, renderData.globalSetUniformBuffer, 0, sizeof(RenderData::GlobalSetUniformBuffer));
uint8_t* imageData = new uint8_t[16*16*4]; std::vector<gfx::DescriptorSetLayoutBinding> frameSetBindings;
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<gfx::DescriptorSetLayoutBinding> setOneLayoutBindings;
{ {
auto& binding0 = setOneLayoutBindings.emplace_back(); auto& binding0 = frameSetBindings.emplace_back();
binding0.descriptorType = gfx::DescriptorType::UNIFORM_BUFFER; binding0.descriptorType = gfx::DescriptorType::UNIFORM_BUFFER;
binding0.stageFlags = gfx::ShaderStageFlags::VERTEX; binding0.stageFlags = gfx::ShaderStageFlags::VERTEX;
} }
renderData.setOneLayout = gfx()->createDescriptorSetLayout(setOneLayoutBindings); renderData.frameSetLayout = gfx()->createDescriptorSetLayout(frameSetBindings);
renderData.setOne = gfx()->allocateDescriptorSet(renderData.setOneLayout); renderData.frameSet = gfx()->allocateDescriptorSet(renderData.frameSetLayout);
RenderData::SetOneBuffer initialSetOneData{ RenderData::FrameSetUniformBuffer initialSetOneData{
.view = glm::mat4{ 1.0f }, .view = glm::mat4{ 1.0f },
}; };
renderData.setOneBuffer = gfx()->createUniformBuffer(sizeof(RenderData::SetOneBuffer), &initialSetOneData); renderData.frameSetUniformBuffer = gfx()->createUniformBuffer(sizeof(RenderData::FrameSetUniformBuffer), &initialSetOneData);
gfx()->updateDescriptorUniformBuffer(renderData.setOne, 0, renderData.setOneBuffer, 0, sizeof(RenderData::SetOneBuffer)); gfx()->updateDescriptorUniformBuffer(renderData.frameSet, 0, renderData.frameSetUniformBuffer, 0, sizeof(RenderData::FrameSetUniformBuffer));
std::vector<gfx::DescriptorSetLayoutBinding> 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 // default resources
{ {
@ -135,11 +128,11 @@ namespace engine {
); );
getResourceManager<resources::Shader>()->addPersistent("builtin.standard", std::move(texturedShader)); getResourceManager<resources::Shader>()->addPersistent("builtin.standard", std::move(texturedShader));
} }
if (0) { {
resources::Shader::VertexParams vertParams{}; resources::Shader::VertexParams vertParams{};
vertParams.hasNormal = true; vertParams.hasNormal = true;
vertParams.hasUV0 = true; vertParams.hasUV0 = true;
auto texturedShader = std::make_unique<resources::Shader>( auto skyboxShader = std::make_unique<resources::Shader>(
&renderData, &renderData,
getResourcePath("engine/shaders/skybox.vert").c_str(), getResourcePath("engine/shaders/skybox.vert").c_str(),
getResourcePath("engine/shaders/skybox.frag").c_str(), getResourcePath("engine/shaders/skybox.frag").c_str(),
@ -147,11 +140,13 @@ namespace engine {
false, false,
true true
); );
getResourceManager<resources::Shader>()->addPersistent("builtin.skybox", std::move(texturedShader)); getResourceManager<resources::Shader>()->addPersistent("builtin.skybox", std::move(skyboxShader));
} }
{ {
auto whiteTexture = std::make_unique<resources::Texture>( auto whiteTexture = std::make_unique<resources::Texture>(
gfx(), gfx(),
renderData.materialSetLayout,
renderData.materialSetSampler,
getResourcePath("engine/textures/white.png"), getResourcePath("engine/textures/white.png"),
resources::Texture::Filtering::OFF, resources::Texture::Filtering::OFF,
false, false,
@ -163,13 +158,14 @@ namespace engine {
Application::~Application() Application::~Application()
{ {
gfx()->destroyUniformBuffer(renderData.setOneBuffer); gfx()->destroySampler(renderData.materialSetSampler);
gfx()->destroyDescriptorSetLayout(renderData.setOneLayout); gfx()->destroyDescriptorSetLayout(renderData.materialSetLayout);
gfx()->destroySampler(renderData.mySampler); gfx()->destroyUniformBuffer(renderData.frameSetUniformBuffer);
gfx()->destroyImage(renderData.myImage); gfx()->destroyDescriptorSetLayout(renderData.frameSetLayout);
gfx()->destroyUniformBuffer(renderData.setZeroBuffer);
gfx()->destroyDescriptorSetLayout(renderData.setZeroLayout); gfx()->destroyUniformBuffer(renderData.globalSetUniformBuffer);
gfx()->destroyDescriptorSetLayout(renderData.globalSetLayout);
} }
void Application::gameLoop() void Application::gameLoop()

View File

@ -104,10 +104,6 @@ namespace engine {
VkSampler sampler = VK_NULL_HANDLE; VkSampler sampler = VK_NULL_HANDLE;
}; };
struct gfx::Texture {
};
struct gfx::DrawBuffer { struct gfx::DrawBuffer {
FrameData frameData{}; FrameData frameData{};
uint32_t currentFrameIndex = 0; // corresponds to the frameData uint32_t currentFrameIndex = 0; // corresponds to the frameData
@ -322,7 +318,10 @@ namespace engine {
VkDescriptorPool descriptorPool; VkDescriptorPool descriptorPool;
std::array<std::unordered_set<gfx::UniformBuffer*>, FRAMES_IN_FLIGHT> uniformBufferWriteQueues{}; std::array<std::unordered_set<gfx::UniformBuffer*>, FRAMES_IN_FLIGHT> uniformBufferWriteQueues{};
// For one-off transfer operations not bound to a specific frame-in-flight
VkCommandPool transferCommandPool = VK_NULL_HANDLE; 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; uint64_t FRAMECOUNT = 0;
@ -483,16 +482,25 @@ namespace engine {
.queueFamilyIndex = pimpl->device.queues.transferQueueFamily .queueFamilyIndex = pimpl->device.queues.transferQueueFamily
}; };
VKCHECK(vkCreateCommandPool(pimpl->device.device, &transferPoolInfo, nullptr, &pimpl->transferCommandPool)); 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 */ /* create a global descriptor pool */
std::vector<VkDescriptorPoolSize> poolSizes{}; std::vector<VkDescriptorPoolSize> 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{}; VkDescriptorPoolCreateInfo descriptorPoolInfo{};
descriptorPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; descriptorPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
descriptorPoolInfo.pNext = nullptr; descriptorPoolInfo.pNext = nullptr;
descriptorPoolInfo.flags = 0; descriptorPoolInfo.flags = 0;
descriptorPoolInfo.maxSets = 100; // purposely low limit descriptorPoolInfo.maxSets = 1000u;
descriptorPoolInfo.poolSizeCount = (uint32_t)poolSizes.size(); descriptorPoolInfo.poolSizeCount = (uint32_t)poolSizes.size();
descriptorPoolInfo.pPoolSizes = poolSizes.data(); descriptorPoolInfo.pPoolSizes = poolSizes.data();
VKCHECK(vkCreateDescriptorPool(pimpl->device.device, &descriptorPoolInfo, nullptr, &pimpl->descriptorPool)); VKCHECK(vkCreateDescriptorPool(pimpl->device.device, &descriptorPoolInfo, nullptr, &pimpl->descriptorPool));
@ -503,6 +511,7 @@ namespace engine {
{ {
vkDestroyDescriptorPool(pimpl->device.device, pimpl->descriptorPool, nullptr); vkDestroyDescriptorPool(pimpl->device.device, pimpl->descriptorPool, nullptr);
vkDestroyCommandPool(pimpl->device.device, pimpl->graphicsCommandPool, nullptr);
vkDestroyCommandPool(pimpl->device.device, pimpl->transferCommandPool, nullptr); vkDestroyCommandPool(pimpl->device.device, pimpl->transferCommandPool, nullptr);
for (uint32_t i = 0; i < FRAMES_IN_FLIGHT; i++) { 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() gfx::DrawBuffer* GFXDevice::beginRender()
{ {
VkResult res; VkResult res;
@ -951,7 +958,7 @@ namespace engine {
depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
depthStencil.depthTestEnable = VK_TRUE; depthStencil.depthTestEnable = VK_TRUE;
depthStencil.depthWriteEnable = 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.depthBoundsTestEnable = VK_FALSE;
depthStencil.minDepthBounds = 0.0f; depthStencil.minDepthBounds = 0.0f;
depthStencil.maxDepthBounds = 1.0f; depthStencil.maxDepthBounds = 1.0f;
@ -1315,7 +1322,7 @@ namespace engine {
imageInfo.arrayLayers = 1; imageInfo.arrayLayers = 1;
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; 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.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
@ -1343,7 +1350,7 @@ namespace engine {
VkCommandBufferAllocateInfo allocInfo{}; VkCommandBufferAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandPool = pimpl->transferCommandPool; allocInfo.commandPool = pimpl->graphicsCommandPool;
allocInfo.commandBufferCount = 1; allocInfo.commandBufferCount = 1;
VkCommandBuffer commandBuffer; VkCommandBuffer commandBuffer;
@ -1363,8 +1370,8 @@ namespace engine {
barrier.dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT; barrier.dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT;
barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barrier.srcQueueFamilyIndex = pimpl->device.queues.transferQueueFamily; barrier.srcQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily;
barrier.dstQueueFamilyIndex = pimpl->device.queues.transferQueueFamily; barrier.dstQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily;
barrier.image = out->image; barrier.image = out->image;
barrier.subresourceRange = viewInfo.subresourceRange; barrier.subresourceRange = viewInfo.subresourceRange;
@ -1397,7 +1404,7 @@ namespace engine {
barrier.dstAccessMask = VK_ACCESS_2_SHADER_SAMPLED_READ_BIT; barrier.dstAccessMask = VK_ACCESS_2_SHADER_SAMPLED_READ_BIT;
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_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; barrier.dstQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily;
vkCmdPipelineBarrier2(commandBuffer, &depInfo); vkCmdPipelineBarrier2(commandBuffer, &depInfo);
@ -1411,11 +1418,11 @@ namespace engine {
submitInfo.commandBufferCount = 1; submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBuffer; 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); vmaDestroyBuffer(pimpl->allocator, stagingBuffer, stagingAllocation);
@ -1436,15 +1443,15 @@ namespace engine {
VkSamplerCreateInfo samplerInfo{}; VkSamplerCreateInfo samplerInfo{};
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
samplerInfo.magFilter = VK_FILTER_NEAREST; samplerInfo.magFilter = VK_FILTER_NEAREST;
samplerInfo.minFilter = VK_FILTER_NEAREST; samplerInfo.minFilter = VK_FILTER_LINEAR;
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerInfo.addressModeW = 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.anisotropyEnable = VK_FALSE;
samplerInfo.minLod = 0.0f; samplerInfo.minLod = 0.0f;
samplerInfo.maxLod = 0.0f; samplerInfo.maxLod = VK_LOD_CLAMP_NONE;
VKCHECK(vkCreateSampler(pimpl->device.device, &samplerInfo, nullptr, &out->sampler)); VKCHECK(vkCreateSampler(pimpl->device.device, &samplerInfo, nullptr, &out->sampler));
@ -1457,32 +1464,6 @@ namespace engine {
delete sampler; 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() void GFXDevice::logPerformanceInfo()
{ {
VmaTotalStatistics pStats{}; VmaTotalStatistics pStats{};
@ -1517,4 +1498,4 @@ namespace engine {
vkDeviceWaitIdle(pimpl->device.device); vkDeviceWaitIdle(pimpl->device.device);
} }
} }

View File

@ -44,8 +44,9 @@ namespace engine::resources {
info.vertexFormat = vertFormat; info.vertexFormat = vertFormat;
info.alphaBlending = alphaBlending; info.alphaBlending = alphaBlending;
info.backfaceCulling = cullBackFace; info.backfaceCulling = cullBackFace;
info.descriptorSetLayouts.push_back(renderData->setZeroLayout); info.descriptorSetLayouts.push_back(renderData->globalSetLayout);
info.descriptorSetLayouts.push_back(renderData->setOneLayout); info.descriptorSetLayouts.push_back(renderData->frameSetLayout);
info.descriptorSetLayouts.push_back(renderData->materialSetLayout);
m_pipeline = m_gfx->createPipeline(info); m_pipeline = m_gfx->createPipeline(info);

View File

@ -7,12 +7,12 @@
namespace engine::resources { 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) : m_gfxDevice(gfxDevice)
{ {
int width, height; int width, height;
auto texbuf = util::readImageFile(path, &width, &height); std::unique_ptr<std::vector<uint8_t>> texbuf = util::readImageFile(path, &width, &height);
gfx::TextureFilter minFilter = gfx::TextureFilter::NEAREST; gfx::TextureFilter minFilter = gfx::TextureFilter::NEAREST;
gfx::TextureFilter magFilter = 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; mipmapSetting = gfx::MipmapSetting::OFF;
} }
m_gpuTexture = m_gfxDevice->createTexture( (void)minFilter;
texbuf->data(), (uint32_t)width, (uint32_t)height, (void)magFilter;
minFilter, magFilter, (void)mipmapSetting;
mipmapSetting, (void)anisotropyEnable;
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); 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() Texture::~Texture()
{ {
m_gfxDevice->destroyTexture(m_gpuTexture); m_gfxDevice->destroyImage(m_image);
}
gfx::Texture* Texture::getHandle()
{
return m_gpuTexture;
} }
} }

View File

@ -45,16 +45,16 @@ namespace engine {
const float verticalFovRadians = glm::radians(m_camera.verticalFovDegrees); const float verticalFovRadians = glm::radians(m_camera.verticalFovDegrees);
const glm::mat4 projMatrix = glm::perspectiveZO(verticalFovRadians, m_viewportAspectRatio, m_camera.clipNear, m_camera.clipFar); const glm::mat4 projMatrix = glm::perspectiveZO(verticalFovRadians, m_viewportAspectRatio, m_camera.clipNear, m_camera.clipFar);
/* update SET 0 */ /* update SET 0 */
RenderData::SetZeroBuffer setZeroBuffer{ RenderData::GlobalSetUniformBuffer globalSetUniformBuffer{
.proj = projMatrix .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 .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 */ /* render all renderable entities */
@ -65,6 +65,7 @@ namespace engine {
struct DrawCallData { struct DrawCallData {
const gfx::Buffer* vb; const gfx::Buffer* vb;
const gfx::Buffer* ib; const gfx::Buffer* ib;
const gfx::DescriptorSet* materialSet;
uint32_t indexCount; uint32_t indexCount;
PushConstants pushConsts; PushConstants pushConsts;
}; };
@ -75,6 +76,7 @@ namespace engine {
auto r = m_scene->getComponent<RenderableComponent>(entity); auto r = m_scene->getComponent<RenderableComponent>(entity);
assert(r != nullptr); assert(r != nullptr);
assert(r->material != nullptr); assert(r->material != nullptr);
assert(r->material->m_texture != nullptr);
assert(r->mesh != nullptr); assert(r->mesh != nullptr);
if (r->shown == false) continue; if (r->shown == false) continue;
@ -85,6 +87,7 @@ namespace engine {
DrawCallData data{}; DrawCallData data{};
data.vb = r->mesh->getVB(); data.vb = r->mesh->getVB();
data.ib = r->mesh->getIB(); data.ib = r->mesh->getIB();
data.materialSet = r->material->m_texture->getDescriptorSet();
data.indexCount = r->mesh->getCount(); data.indexCount = r->mesh->getCount();
data.pushConsts.model = t->worldMatrix; data.pushConsts.model = t->worldMatrix;
@ -97,12 +100,15 @@ namespace engine {
/* these descriptor set bindings should persist across pipeline changes */ /* these descriptor set bindings should persist across pipeline changes */
const gfx::Pipeline* firstPipeline = pipelineDrawCalls.begin()->first; const gfx::Pipeline* firstPipeline = pipelineDrawCalls.begin()->first;
m_gfx->cmdBindDescriptorSet(renderData.drawBuffer, firstPipeline, renderData.setZero, 0); m_gfx->cmdBindDescriptorSet(renderData.drawBuffer, firstPipeline, renderData.globalSet, 0);
m_gfx->cmdBindDescriptorSet(renderData.drawBuffer, firstPipeline, renderData.setOne, 1); m_gfx->cmdBindDescriptorSet(renderData.drawBuffer, firstPipeline, renderData.frameSet, 1);
for (const auto& [pipeline, drawCalls] : pipelineDrawCalls) { for (const auto& [pipeline, drawCalls] : pipelineDrawCalls) {
m_gfx->cmdBindPipeline(renderData.drawBuffer, pipeline); m_gfx->cmdBindPipeline(renderData.drawBuffer, pipeline);
for (const auto& drawCall : drawCalls) { 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->cmdPushConstants(renderData.drawBuffer, pipeline, 0, sizeof(PushConstants), &drawCall.pushConsts);
m_gfx->cmdBindVertexBuffer(renderData.drawBuffer, 0, drawCall.vb); m_gfx->cmdBindVertexBuffer(renderData.drawBuffer, 0, drawCall.vb);
m_gfx->cmdBindIndexBuffer(renderData.drawBuffer, drawCall.ib); m_gfx->cmdBindIndexBuffer(renderData.drawBuffer, drawCall.ib);

View File

@ -51,7 +51,6 @@ namespace engine::util {
return buffer; return buffer;
} }
// Read an image file into a vector byte buffer. PNG and JPG support at a minimum
std::unique_ptr<std::vector<uint8_t>> readImageFile(const std::string& path, int *width, int *height) std::unique_ptr<std::vector<uint8_t>> readImageFile(const std::string& path, int *width, int *height)
{ {
int x, y, n; int x, y, n;

View File

@ -182,7 +182,7 @@ namespace engine::util {
absPath /= texPath.C_Str(); absPath /= texPath.C_Str();
try { try {
textures[i] = std::make_shared<resources::Texture>( textures[i] = std::make_shared<resources::Texture>(
parent->app()->gfx(), absPath.string(), parent->app()->gfx(), parent->app()->renderData.materialSetLayout, parent->app()->renderData.materialSetSampler, absPath.string(),
resources::Texture::Filtering::TRILINEAR, true, true); resources::Texture::Filtering::TRILINEAR, true, true);
} catch (const std::runtime_error&) { } catch (const std::runtime_error&) {
textures[i] = parent->app()->getResource<resources::Texture>("builtin.white"); textures[i] = parent->app()->getResource<resources::Texture>("builtin.white");

View File

@ -85,6 +85,8 @@ void playGame(GameSettings settings)
/* shared resources */ /* shared resources */
auto grassTexture = std::make_shared<engine::resources::Texture>( auto grassTexture = std::make_shared<engine::resources::Texture>(
app.gfx(), app.gfx(),
app.renderData.materialSetLayout,
app.renderData.materialSetSampler,
app.getResourcePath("textures/grass.jpg"), app.getResourcePath("textures/grass.jpg"),
engine::resources::Texture::Filtering::ANISOTROPIC, engine::resources::Texture::Filtering::ANISOTROPIC,
true, true,
@ -92,29 +94,21 @@ void playGame(GameSettings settings)
); );
auto spaceTexture = std::make_shared<engine::resources::Texture>( auto spaceTexture = std::make_shared<engine::resources::Texture>(
app.gfx(), app.gfx(),
app.renderData.materialSetLayout,
app.renderData.materialSetSampler,
app.getResourcePath("textures/space2.png"), app.getResourcePath("textures/space2.png"),
engine::resources::Texture::Filtering::ANISOTROPIC, engine::resources::Texture::Filtering::ANISOTROPIC,
true, true,
true true
); );
/* skybox */
if (0) {
uint32_t skybox = myScene->createEntity("skybox");
auto skyboxRenderable = myScene->addComponent<engine::RenderableComponent>(skybox);
skyboxRenderable->material = std::make_unique<engine::resources::Material>(app.getResource<engine::resources::Shader>("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<engine::TransformComponent>(skybox)->position = { -5.0f, -5.0f, -5.0f };
}
/* cube */ /* cube */
{ {
uint32_t cube = myScene->createEntity("cube"); uint32_t cube = myScene->createEntity("cube");
myScene->getComponent<engine::TransformComponent>(cube)->position = glm::vec3{ -0.5f + 5.0f, -0.5f + 5.0f, -0.5f + 5.0f }; myScene->getComponent<engine::TransformComponent>(cube)->position = glm::vec3{ -0.5f + 5.0f, -0.5f + 5.0f, -0.5f + 5.0f };
auto cubeRenderable = myScene->addComponent<engine::RenderableComponent>(cube); auto cubeRenderable = myScene->addComponent<engine::RenderableComponent>(cube);
cubeRenderable->material = std::make_shared<engine::resources::Material>(app.getResource<engine::resources::Shader>("builtin.standard")); cubeRenderable->material = std::make_shared<engine::resources::Material>(app.getResource<engine::resources::Shader>("builtin.standard"));
cubeRenderable->material->m_texture = app.getResource<engine::resources::Texture>("builtin.white");
cubeRenderable->mesh = genCuboidMesh(app.gfx(), 1.0f, 1.0f, 1.0f, 1); cubeRenderable->mesh = genCuboidMesh(app.gfx(), 1.0f, 1.0f, 1.0f, 1);
auto cubeCollider = myScene->addComponent<engine::ColliderComponent>(cube); auto cubeCollider = myScene->addComponent<engine::ColliderComponent>(cube);
cubeCollider->isStatic = true; cubeCollider->isStatic = true;
@ -137,6 +131,16 @@ void playGame(GameSettings settings)
//engine::util::loadMeshFromFile(myScene, app.getResourcePath("models/astronaut/astronaut.dae")); //engine::util::loadMeshFromFile(myScene, app.getResourcePath("models/astronaut/astronaut.dae"));
/* skybox */
{
uint32_t skybox = myScene->createEntity("skybox");
auto skyboxRenderable = myScene->addComponent<engine::RenderableComponent>(skybox);
skyboxRenderable->material = std::make_unique<engine::resources::Material>(app.getResource<engine::resources::Shader>("builtin.skybox"));
skyboxRenderable->material->m_texture = spaceTexture;
skyboxRenderable->mesh = genCuboidMesh(app.gfx(), 10.0f, 10.0f, 10.0f, 1.0f, true);
myScene->getComponent<engine::TransformComponent>(skybox)->position = { -5.0f, -5.0f, -5.0f };
}
app.gameLoop(); app.gameLoop();
} }