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;
/* 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 {

View File

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

View File

@ -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();

View File

@ -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;
};
}

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<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);
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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

View File

@ -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));
}

View File

@ -14,7 +14,7 @@
#include "resources/shader.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
#include <thread>
@ -76,49 +76,42 @@ namespace engine {
// initialise the render data
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.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<gfx::DescriptorSetLayoutBinding> setOneLayoutBindings;
std::vector<gfx::DescriptorSetLayoutBinding> 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<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
{
@ -135,11 +128,11 @@ namespace engine {
);
getResourceManager<resources::Shader>()->addPersistent("builtin.standard", std::move(texturedShader));
}
if (0) {
{
resources::Shader::VertexParams vertParams{};
vertParams.hasNormal = true;
vertParams.hasUV0 = true;
auto texturedShader = std::make_unique<resources::Shader>(
auto skyboxShader = std::make_unique<resources::Shader>(
&renderData,
getResourcePath("engine/shaders/skybox.vert").c_str(),
getResourcePath("engine/shaders/skybox.frag").c_str(),
@ -147,11 +140,13 @@ namespace engine {
false,
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>(
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()

View File

@ -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<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;
// 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<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{};
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);
}
}
}

View File

@ -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);

View File

@ -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<std::vector<uint8_t>> 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);
}
}

View File

@ -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<RenderableComponent>(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);

View File

@ -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<std::vector<uint8_t>> readImageFile(const std::string& path, int *width, int *height)
{
int x, y, n;

View File

@ -182,7 +182,7 @@ namespace engine::util {
absPath /= texPath.C_Str();
try {
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);
} catch (const std::runtime_error&) {
textures[i] = parent->app()->getResource<resources::Texture>("builtin.white");

View File

@ -85,6 +85,8 @@ void playGame(GameSettings settings)
/* shared resources */
auto grassTexture = std::make_shared<engine::resources::Texture>(
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<engine::resources::Texture>(
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<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 */
{
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 };
auto cubeRenderable = myScene->addComponent<engine::RenderableComponent>(cube);
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);
auto cubeCollider = myScene->addComponent<engine::ColliderComponent>(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<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();
}