Commit 2a256434 authored by Lukas Tietze's avatar Lukas Tietze

Texture-Klasse

parent 3397dcee
......@@ -23,6 +23,8 @@
url = https://github.com/ocornut/imgui.git
ignore = untracked
branch = master
[submodule "stb"]
path = .\\src\\submodules\\stb
url = https://github.com/nothings/stb.git
[submodule "stb"]
path = src/submodules/stb
url = https://github.com/nothings/stb.git
ignore = untracked
branch = master
......@@ -61,13 +61,15 @@ add_library(
src/Lib/src/VkUtil/CompileShader.cpp
src/Lib/src/VkUtil/AccelerationStructureBase.cpp
src/Lib/src/VkUtil/BottomLevelAccelerationStructure.cpp
src/Lib/src/VkUtil/FindOptimalMemoryType.cpp
src/Lib/src/VkUtil/VkUtil.cpp
src/Lib/src/VkUtil/NoUsableMemoryException.cpp
src/Lib/src/VkUtil/TopLevelAccelerationStructure.cpp
src/Lib/src/VkUtil/VkResult.cpp
src/Lib/src/VkUtil/Buffer.cpp
src/Lib/src/VkUtil/Texture.cpp
src/Lib/src/VkUtil/StagedBuffer.cpp
src/Lib/src/VkUtil/OneTimeCommandBuffer.cpp
src/Lib/src/VkUtil/StbImageImpl.cpp
src/submodules/dearImGui/imgui_demo.cpp
src/submodules/dearImGui/imgui_draw.cpp
......@@ -88,6 +90,7 @@ target_include_directories(Lib
${CMAKE_CURRENT_SOURCE_DIR}/src/submodules/assimp/include
${CMAKE_CURRENT_SOURCE_DIR}/src/submodules/dearImGui
${CMAKE_CURRENT_SOURCE_DIR}/src/submodules/dearImGui/examples
${CMAKE_CURRENT_SOURCE_DIR}/src/submodules/stb
)
target_link_libraries(Lib
......@@ -126,6 +129,7 @@ target_include_directories(App
${CMAKE_CURRENT_SOURCE_DIR}/src/submodules/assimp/include
${CMAKE_CURRENT_SOURCE_DIR}/src/submodules/dearImGui
${CMAKE_CURRENT_SOURCE_DIR}/src/submodules/dearImGui/examples
${CMAKE_CURRENT_SOURCE_DIR}/src/submodules/stb
${CMAKE_CURRENT_SOURCE_DIR}/src/App/include
)
......@@ -158,6 +162,7 @@ target_include_directories(Playground
${CMAKE_CURRENT_SOURCE_DIR}/src/submodules/assimp/include
${CMAKE_CURRENT_SOURCE_DIR}/src/submodules/dearImGui
${CMAKE_CURRENT_SOURCE_DIR}/src/submodules/dearImGui/examples
${CMAKE_CURRENT_SOURCE_DIR}/src/submodules/stb
${CMAKE_CURRENT_SOURCE_DIR}/src/Lib/include
${CMAKE_CURRENT_SOURCE_DIR}/src/App/include
)
......
......@@ -151,6 +151,7 @@ namespace lib
std::unique_ptr<Buffer> materialsBuffer;
std::unique_ptr<Buffer> objectInstancesBuffer;
std::unique_ptr<Buffer> lightSourcesBuffer;
std::unique_ptr<Texture> dummyTexture; // TODO: dummy
struct PushConstants
{
......
......@@ -34,6 +34,7 @@ public:
Buffer &operator=(const Buffer &copy) = delete;
Buffer &operator=(Buffer &&other);
operator vk::Buffer() const;
void Destroy();
std::tuple<vk::Buffer, vk::DeviceMemory> Disown();
......
#pragma once
#include <string>
#include <memory>
#include <exception>
#include "GlfwAndVulkan.hpp"
#include "VkUtil/Buffer.hpp"
......@@ -16,7 +18,13 @@ namespace lib
{
private:
CgContext *parent;
lib::Buffer buffer;
vk::Format format;
vk::Image image;
vk::DeviceMemory memory;
void LoadData(uint32_t width, uint32_t height, const void *data, uint8_t pixelByteCount);
constexpr DefaultFormat = vk::Format::eR8G8B8A8Srgb;
public:
/**
......@@ -26,7 +34,7 @@ namespace lib
* @param format Das Format der Daten, Standard ist RGBA mit 8 bit pro Kanal.
* @param path Der Pfad zur Quelldatei.
*/
Texture(const std::string &path, vk::Format format = vk::Format::eR8G8B8A8Uint);
Texture(CgContext *parent, const std::string &path, vk::Format format = DefaultFormat);
/**
* @brief Initialisiert eine neue Instanz der Texture Klasse und l盲dt die Daten aus einem Puffer.
......@@ -34,9 +42,10 @@ namespace lib
* @param width Die Breite in Pixeln.
* @param height Die H枚he in Pixeln.
* @param data Die Daten als byte-Array.
* @param format Das Format der Daten, Standard ist RGBA mit 8 bit pro Kanal.
* @param pixelByteCount bytes pro Pixel.
* @param format Das Zielformat der Daten, Standard ist RGBA mit 8 bit pro Kanal.
*/
Texture(uint32_t width, uint32_t height, const uint8_t *data, vk::Format format = vk::Format::eR8G8B8A8Uint);
Texture(CgContext *parent, uint32_t width, uint32_t height, uint8_t pixelByteCount, const void *data, vk::Format format = DefaultFormat);
/**
* @brief Initialisiert eine neue Instanz der Texture Klasse und erzeugt die Daten mittels
......@@ -49,8 +58,24 @@ namespace lib
* @param format Das Format der Daten, Standard ist RGBA mit 8 bit pro Kanal.
*/
template <typename T>
Texture(uint32_t width, uint32_t height, T generator, vk::Format format = vk::Format::eR8G8B8A8Uint)
Texture(CgContext *parent, uint32_t width, uint32_t height, T &generator, vk::Format format = DefaultFormat) : parent(parent),
format(format)
{
std::vector<decltype(generator(uint32_t{0}, uint32_t{0}))> buf(width * height);
for (uint32_t x = 0; x < width; x++)
{
for (uint32_t y = 0; y < height; y++)
{
buf[y * width + x] = generator(x, y);
}
}
this->LoadData(width, height, buf.data(), sizeof(buf.front()));
}
~Texture();
const vk::Image &getHandle();
}; // namespace lib
} // namespace lib
......@@ -12,75 +12,82 @@
#include <exception>
namespace lib
{
/**
* @brief Schreibt die Beschreibung eines [vk::Result] in einen Stream.
*
* Siehe: https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vk::Result.html
*/
std::ostream &operator<<(std::ostream &, const vk::Result &);
uint32_t FindOptimalMemoryType(uint32_t typeFilter, const vk::PhysicalDeviceMemoryProperties &memoryProperties, vk::MemoryPropertyFlags flags);
class NoUsableMemoryException : public std::exception
{
public:
NoUsableMemoryException(uint32_t typeFilter, vk::MemoryPropertyFlags flags);
};
/**
* @brief Stellt eine Instanz eines Geometrie-Objekts dar.
*/
struct GeometryInstance
{
/**
* @brief Der Buffer in dem die Vertex-Daten liegen.
* @brief Schreibt die Beschreibung eines [vk::Result] in einen Stream.
*
* Siehe: https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vk::Result.html
*/
vk::Buffer vertexBuffer;
std::ostream &operator<<(std::ostream &, const vk::Result &);
/**
* @brief Die Anzahl an Vertices, die zu dieser Instanz geh枚ren.
*/
uint32_t vertexCount = 0;
uint32_t FindOptimalMemoryType(uint32_t typeFilter, const vk::PhysicalDeviceMemoryProperties &memoryProperties, vk::MemoryPropertyFlags flags);
/**
* @brief Offset in Bytes zum ersten zu nutzenden Vertex.
*/
vk::DeviceSize vertexOffset = 0;
void TransitionImageLayout(vk::CommandBuffer commandBuffer,
vk::Image image,
vk::Format format,
vk::ImageLayout oldLayout,
vk::ImageLayout newLayout,
vk::PipelineStageFlagBits srcStage,
vk::PipelineStageFlagBits dstStage);
/**
* @brief Der Buffer in dem die Index-Daten liegen.
*/
vk::Buffer indexBuffer;
class NoUsableMemoryException : public std::exception
{
public:
NoUsableMemoryException(uint32_t typeFilter, vk::MemoryPropertyFlags flags);
};
/**
* @brief Die Anzahl an Indices, die zu dieser Instanz geh枚ren.
* @brief Stellt eine Instanz eines Geometrie-Objekts dar.
*/
uint32_t indexCount = 0;
/**
* @brief Offset inBytes zum ersten zu nutzenden Index.
*/
vk::DeviceSize indexOffset = 0;
/**
* @brief Die Transformationsmatrix der Instanz.
*/
glm::mat4 transformationMatrix = {};
/**
* @brief Gibt an, ob die Vertices der Instanz undurchsichtig sind oder nicht.
*/
bool isOpaque = true;
};
template <typename T>
constexpr vk::IndexType IndexTypeOf = vk::_INDEX_TYPE_MAX_ENUM;
template <>
constexpr vk::IndexType IndexTypeOf<uint16_t> = vk::IndexType::eUint16;
template <>
constexpr vk::IndexType IndexTypeOf<uint32_t> = vk::IndexType::eUint32;
struct GeometryInstance
{
/**
* @brief Der Buffer in dem die Vertex-Daten liegen.
*/
vk::Buffer vertexBuffer;
/**
* @brief Die Anzahl an Vertices, die zu dieser Instanz geh枚ren.
*/
uint32_t vertexCount = 0;
/**
* @brief Offset in Bytes zum ersten zu nutzenden Vertex.
*/
vk::DeviceSize vertexOffset = 0;
/**
* @brief Der Buffer in dem die Index-Daten liegen.
*/
vk::Buffer indexBuffer;
/**
* @brief Die Anzahl an Indices, die zu dieser Instanz geh枚ren.
*/
uint32_t indexCount = 0;
/**
* @brief Offset inBytes zum ersten zu nutzenden Index.
*/
vk::DeviceSize indexOffset = 0;
/**
* @brief Die Transformationsmatrix der Instanz.
*/
glm::mat4 transformationMatrix = {};
/**
* @brief Gibt an, ob die Vertices der Instanz undurchsichtig sind oder nicht.
*/
bool isOpaque = true;
};
template <typename T>
constexpr vk::IndexType IndexTypeOf = vk::_INDEX_TYPE_MAX_ENUM;
template <>
constexpr vk::IndexType IndexTypeOf<uint16_t> = vk::IndexType::eUint16;
template <>
constexpr vk::IndexType IndexTypeOf<uint32_t> = vk::IndexType::eUint32;
} // namespace lib
\ No newline at end of file
......@@ -712,25 +712,6 @@ void lib::CgContext::UpdateCommandBuffer(uint32_t imageIndex)
auto sbtEntrySize = this->physicalDeviceInfo.GetRaytracingProperties().shaderGroupHandleSize;
vk::ImageSubresourceRange subresourceRange;
subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor;
subresourceRange.baseArrayLayer = 0;
subresourceRange.layerCount = 1;
subresourceRange.baseMipLevel = 0;
subresourceRange.levelCount = 1;
vk::ImageMemoryBarrier transitionToGeneralLayout;
transitionToGeneralLayout.oldLayout = vk::ImageLayout::eUndefined;
transitionToGeneralLayout.newLayout = vk::ImageLayout::eGeneral;
transitionToGeneralLayout.image = this->swapChainImages[imageIndex];
transitionToGeneralLayout.subresourceRange = subresourceRange;
vk::ImageMemoryBarrier transitionToFinalLayout;
transitionToFinalLayout.oldLayout = vk::ImageLayout::eGeneral;
transitionToFinalLayout.newLayout = vk::ImageLayout::ePresentSrcKHR;
transitionToFinalLayout.image = this->swapChainImages[imageIndex];
transitionToFinalLayout.subresourceRange = subresourceRange;
if (this->IsOk())
{
commandBuffer.bindPipeline(vk::PipelineBindPoint::eRayTracingNV, this->pipeline);
......@@ -738,21 +719,23 @@ void lib::CgContext::UpdateCommandBuffer(uint32_t imageIndex)
0, this->descriptorSets[imageIndex], {});
}
commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe,
vk::PipelineStageFlagBits::eRayTracingShaderNV,
vk::DependencyFlagBits::eByRegion,
{}, {}, transitionToGeneralLayout);
commandBuffer.pushConstants(this->pipelineLayout,
vk::ShaderStageFlagBits::eRaygenNV | vk::ShaderStageFlagBits::eClosestHitNV,
0, sizeof(this->pushConstant),
&this->pushConstant);
TransitionImageLayout(commandBuffer,
this->swapChainImages[imageIndex], this->swapChainImageFormat,
vk::ImageLayout::eUndefined, vk::ImageLayout::eGeneral,
vk::PipelineStageFlagBits::eTopOfPipe,
vk::PipelineStageFlagBits::eRayTracingShaderNV);
if (this->IsOk())
{
commandBuffer.copyBuffer(this->uniformStagingBuffers[imageIndex].GetBufferHandle(),
this->uniformBuffers[imageIndex].GetBufferHandle(),
vk::BufferCopy(0, 0, this->uniformBuffers[imageIndex].GetSize()));
commandBuffer.pushConstants(this->pipelineLayout,
vk::ShaderStageFlagBits::eRaygenNV | vk::ShaderStageFlagBits::eClosestHitNV,
0, sizeof(this->pushConstant),
&this->pushConstant);
commandBuffer.traceRaysNV(this->shaderBindingTableBuffer->GetBufferHandle(), this->shaderOffsets.rayGen * sbtEntrySize,
this->shaderBindingTableBuffer->GetBufferHandle(), this->shaderOffsets.miss * sbtEntrySize, sbtEntrySize,
this->shaderBindingTableBuffer->GetBufferHandle(), this->shaderOffsets.hitGroup * sbtEntrySize, sbtEntrySize,
......@@ -776,10 +759,11 @@ void lib::CgContext::UpdateCommandBuffer(uint32_t imageIndex)
}
else
{
commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eRayTracingShaderNV,
vk::PipelineStageFlagBits::eBottomOfPipe,
vk::DependencyFlagBits::eByRegion,
{}, {}, transitionToFinalLayout);
TransitionImageLayout(commandBuffer,
this->swapChainImages[imageIndex], this->swapChainImageFormat,
vk::ImageLayout::eGeneral, vk::ImageLayout::ePresentSrcKHR,
vk::PipelineStageFlagBits::eRayTracingShaderNV,
vk::PipelineStageFlagBits::eBottomOfPipe);
}
commandBuffer.end();
......
......@@ -51,6 +51,11 @@ lib::Buffer &lib::Buffer::operator=(Buffer &&other)
return *this;
}
lib::Buffer::operator vk::Buffer() const
{
return this->buffer;
}
const vk::Buffer &lib::Buffer::GetBufferHandle() const
{
return this->buffer;
......
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
\ No newline at end of file
#include "Core/CgContext.hpp"
#include "VkUtil/Texture.hpp"
#include "stb_image.h"
#include "VkUtil/VkUtil.hpp"
lib::Texture::Texture(CgContext *parent, const std::string &path, vk::Format format) : parent(parent),
format(format)
{
int width;
int height;
int texChannels;
stbi_uc *pixels = stbi_load(path.c_str(), &width, &height, &texChannels, STBI_rgb_alpha);
if (!pixels)
{
// TODO vllt eigene Klasse machen
throw std::runtime_error("Failed to read image!");
}
this->LoadData(width, height, pixels, texChannels);
stbi_image_free(pixels);
}
lib::Texture::Texture(CgContext *parent, uint32_t width, uint32_t height, uint8_t pixelByteCount, const void *data, vk::Format format) : parent(parent),
format(format)
{
this->LoadData(width, height, data, pixelByteCount);
}
lib::Texture::~Texture()
{
const auto &device = this->parent->GetLogicalDevice();
if (this->image)
{
device.destroyImage(this->image);
this->image = nullptr;
}
if (this->memory)
{
device.freeMemory(this->memory);
this->memory = nullptr;
}
}
void lib::Texture::LoadData(uint32_t width, uint32_t height, const void *data, uint8_t pixelByteCount)
{
auto stagingBuffer = this->parent->CreateStagingSrcBuffer();
stagingBuffer.BufferData(data, width * height * pixelByteCount);
vk::ImageCreateInfo createInfo;
createInfo.imageType = vk::ImageType::e2D;
createInfo.extent.width = width;
createInfo.extent.height = height;
createInfo.extent.depth = 1;
createInfo.mipLevels = 1;
createInfo.arrayLayers = 1;
createInfo.format = this->format;
createInfo.tiling = vk::ImageTiling::eOptimal;
createInfo.initialLayout = vk::ImageLayout::eUndefined;
createInfo.usage = vk::ImageUsageFlagBits::eTransferDst |
vk::ImageUsageFlagBits::eSampled; // TODO: Struktur bauen, die noch bestimmt, wie auf das Bild zugegriffen werden soll.
createInfo.sharingMode = vk::SharingMode::eExclusive;
createInfo.samples = vk::SampleCountFlagBits::e1;
const auto &device = this->parent->GetLogicalDevice();
this->image = device.createImage(createInfo);
vk::MemoryRequirements memoryRequirements = device.getImageMemoryRequirements(this->image);
auto memoryProperties = this->parent->GetPhysicalDeviceInfo().GetHandle().getMemoryProperties();
vk::MemoryAllocateInfo allocateInfo;
allocateInfo.allocationSize = memoryRequirements.size;
allocateInfo.memoryTypeIndex = lib::FindOptimalMemoryType(memoryRequirements.memoryTypeBits,
memoryProperties,
vk::MemoryPropertyFlagBits::eDeviceLocal);
this->memory = device.allocateMemory(allocateInfo);
device.bindImageMemory(this->image, this->memory, 0);
auto commandBuffer = this->parent->AllocateSingleUseStagingCommandBuffer();
vk::BufferImageCopy region;
region.imageSubresource.aspectMask = vk::ImageAspectFlagBits::eColor;
region.imageSubresource.mipLevel = 0;
region.imageSubresource.baseArrayLayer = 0;
region.imageSubresource.layerCount = 1;
region.imageOffset = {0, 0, 0};
region.imageExtent = {width, height, 1};
TransitionImageLayout(commandBuffer, this->image, this->format,
vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal,
vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer);
commandBuffer.GetHandle().copyBufferToImage(stagingBuffer, this->image,
vk::ImageLayout::eTransferDstOptimal, region);
TransitionImageLayout(commandBuffer, this->image, this->format,
vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal, // TODO das muss auch noch ge盲ndert werden wenn die Texture beschrieben werden soll
vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eRayTracingShaderNV);
commandBuffer.Run();
}
const vk::Image &lib::Texture::getHandle()
{
return this->image;
}
\ No newline at end of file
......@@ -11,4 +11,29 @@ uint32_t lib::FindOptimalMemoryType(uint32_t typeFilter, const vk::PhysicalDevic
}
throw lib::NoUsableMemoryException(typeFilter, flags);
}
void lib::TransitionImageLayout(vk::CommandBuffer commandBuffer,
vk::Image image,
vk::Format format,
vk::ImageLayout oldLayout,
vk::ImageLayout newLayout,
vk::PipelineStageFlagBits srcStage,
vk::PipelineStageFlagBits dstStage)
{
vk::ImageSubresourceRange subresourceRange;
subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor;
subresourceRange.baseArrayLayer = 0;
subresourceRange.layerCount = 1;
subresourceRange.baseMipLevel = 0;
subresourceRange.levelCount = 1;
vk::ImageMemoryBarrier barrier;
barrier.oldLayout = oldLayout;
barrier.newLayout = newLayout;
barrier.image = image;
barrier.subresourceRange = subresourceRange;
commandBuffer.pipelineBarrier(srcStage, dstStage, vk::DependencyFlagBits::eByRegion,
{}, {}, barrier);
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment