fixing compilation issues, working on textures

This commit is contained in:
2024-09-04 02:35:01 +02:00
parent e0da415e86
commit 8ad6d84bd2
15 changed files with 315 additions and 115 deletions

View File

@@ -19,7 +19,7 @@
Error("invalid image ptr (NULL)"); \ Error("invalid image ptr (NULL)"); \
retval; \ retval; \
} \ } \
else if(!m_image_registry.IsTextureKnown(img)) \ else if(!m_image_registry.IsTextureKnown(static_cast<Texture*>(img))) \
{ \ { \
Error("invalid image ptr"); \ Error("invalid image ptr"); \
retval; \ retval; \

View File

@@ -29,7 +29,7 @@ namespace mlx
inline void LoadFont(const std::filesystem::path& filepath, float scale); inline void LoadFont(const std::filesystem::path& filepath, float scale);
inline void TryEraseTextureFromRegistry(NonOwningPtr<Texture> texture) noexcept; inline void TryEraseSpritesInScene(NonOwningPtr<Texture> texture) noexcept;
[[nodiscard]] MLX_FORCEINLINE bool HasWindow() const noexcept { return m_has_window; } [[nodiscard]] MLX_FORCEINLINE bool HasWindow() const noexcept { return m_has_window; }
[[nodiscard]] MLX_FORCEINLINE Renderer& GetRenderer() { return m_renderer; } [[nodiscard]] MLX_FORCEINLINE Renderer& GetRenderer() { return m_renderer; }
@@ -42,6 +42,8 @@ namespace mlx
std::shared_ptr<Window> p_window; std::shared_ptr<Window> p_window;
std::unique_ptr<Scene> p_scene; std::unique_ptr<Scene> p_scene;
std::uint64_t m_current_depth = 0;
std::size_t m_width = 0; std::size_t m_width = 0;
std::size_t m_height = 0; std::size_t m_height = 0;

View File

@@ -7,6 +7,7 @@ namespace mlx
{ {
MLX_PROFILE_FUNCTION(); MLX_PROFILE_FUNCTION();
p_scene->ResetSprites(); p_scene->ResetSprites();
m_current_depth = 0;
} }
void GraphicsSupport::PixelPut(int x, int y, std::uint32_t color) noexcept void GraphicsSupport::PixelPut(int x, int y, std::uint32_t color) noexcept
@@ -22,6 +23,15 @@ namespace mlx
void GraphicsSupport::TexturePut(NonOwningPtr<Texture> texture, int x, int y) void GraphicsSupport::TexturePut(NonOwningPtr<Texture> texture, int x, int y)
{ {
MLX_PROFILE_FUNCTION(); MLX_PROFILE_FUNCTION();
NonOwningPtr<Sprite> sprite = p_scene->GetSpriteFromTextureAndPosition(texture, Vec2f{ static_cast<float>(x), static_cast<float>(y) });
if(!sprite)
{
Sprite& new_sprite = p_scene->CreateSprite(texture);
new_sprite.SetPosition(Vec3f{ static_cast<float>(x), static_cast<float>(y), static_cast<float>(m_current_depth) });
}
else
sprite->SetPosition(Vec3f{ static_cast<float>(x), static_cast<float>(y), static_cast<float>(m_current_depth) });
m_current_depth++;
} }
void GraphicsSupport::LoadFont(const std::filesystem::path& filepath, float scale) void GraphicsSupport::LoadFont(const std::filesystem::path& filepath, float scale)
@@ -29,8 +39,9 @@ namespace mlx
MLX_PROFILE_FUNCTION(); MLX_PROFILE_FUNCTION();
} }
void GraphicsSupport::TryEraseTextureFromRegistry(NonOwningPtr<Texture> texture) noexcept void GraphicsSupport::TryEraseSpritesInScene(NonOwningPtr<Texture> texture) noexcept
{ {
MLX_PROFILE_FUNCTION(); MLX_PROFILE_FUNCTION();
p_scene->TryEraseSpriteFromTexture(texture);
} }
} }

View File

@@ -17,7 +17,9 @@ namespace mlx
public: public:
Scene(SceneDescriptor desc); Scene(SceneDescriptor desc);
Sprite& CreateSprite(std::shared_ptr<class Texture> texture) noexcept; Sprite& CreateSprite(NonOwningPtr<class Texture> texture) noexcept;
NonOwningPtr<Sprite> GetSpriteFromTextureAndPosition(NonOwningPtr<Texture> texture, const Vec2f& position) const;
void TryEraseSpriteFromTexture(NonOwningPtr<Texture> texture);
inline void ResetSprites() { m_sprites.clear(); } inline void ResetSprites() { m_sprites.clear(); }

View File

@@ -14,7 +14,7 @@ namespace mlx
friend class Render2DPass; friend class Render2DPass;
public: public:
Sprite(std::shared_ptr<Texture> texture); Sprite(NonOwningPtr<Texture> texture);
inline void SetColor(Vec4f color) noexcept { m_color = color; } inline void SetColor(Vec4f color) noexcept { m_color = color; }
inline void SetPosition(Vec3f position) noexcept { m_position = position; } inline void SetPosition(Vec3f position) noexcept { m_position = position; }
@@ -22,7 +22,7 @@ namespace mlx
[[nodiscard]] inline const Vec4f& GetColor() const noexcept { return m_color; } [[nodiscard]] inline const Vec4f& GetColor() const noexcept { return m_color; }
[[nodiscard]] inline const Vec3f& GetPosition() const noexcept { return m_position; } [[nodiscard]] inline const Vec3f& GetPosition() const noexcept { return m_position; }
[[nodiscard]] inline std::shared_ptr<Mesh> GetMesh() const { return p_mesh; } [[nodiscard]] inline std::shared_ptr<Mesh> GetMesh() const { return p_mesh; }
[[nodiscard]] inline std::shared_ptr<Texture> GetTexture() const { return p_texture; } [[nodiscard]] inline NonOwningPtr<Texture> GetTexture() const { return p_texture; }
~Sprite() = default; ~Sprite() = default;
@@ -43,7 +43,7 @@ namespace mlx
private: private:
DescriptorSet m_set; DescriptorSet m_set;
std::shared_ptr<Texture> p_texture; NonOwningPtr<Texture> p_texture;
std::shared_ptr<Mesh> p_mesh; std::shared_ptr<Mesh> p_mesh;
Vec4f m_color = Vec4f{ 1.0f, 1.0f, 1.0f, 1.0f }; Vec4f m_color = Vec4f{ 1.0f, 1.0f, 1.0f, 1.0f };
Vec3f m_position = Vec3f{ 0.0f, 0.0f, 0.0f }; Vec3f m_position = Vec3f{ 0.0f, 0.0f, 0.0f };

View File

@@ -47,7 +47,7 @@ namespace mlx
virtual ~Image() = default; virtual ~Image() = default;
private: protected:
VmaAllocation m_allocation; VmaAllocation m_allocation;
VkImage m_image = VK_NULL_HANDLE; VkImage m_image = VK_NULL_HANDLE;
VkImageView m_image_view = VK_NULL_HANDLE; VkImageView m_image_view = VK_NULL_HANDLE;
@@ -84,6 +84,7 @@ namespace mlx
{ {
Init(std::move(pixels), width, height, format, is_multisampled); Init(std::move(pixels), width, height, format, is_multisampled);
} }
inline void Init(CPUBuffer pixels, std::uint32_t width, std::uint32_t height, VkFormat format = VK_FORMAT_R8G8B8A8_SRGB, bool is_multisampled = false) inline void Init(CPUBuffer pixels, std::uint32_t width, std::uint32_t height, VkFormat format = VK_FORMAT_R8G8B8A8_SRGB, bool is_multisampled = false)
{ {
Image::Init(ImageType::Color, width, height, format, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, is_multisampled); Image::Init(ImageType::Color, width, height, format, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, is_multisampled);
@@ -91,12 +92,12 @@ namespace mlx
Image::CreateSampler(); Image::CreateSampler();
if(pixels) if(pixels)
{ {
TransitionLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
GPUBuffer staging_buffer; GPUBuffer staging_buffer;
std::size_t size = width * height * kvfFormatSize(format); std::size_t size = width * height * kvfFormatSize(format);
staging_buffer.Init(BufferType::Staging, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, pixels); staging_buffer.Init(BufferType::Staging, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, pixels);
VkCommandBuffer cmd = kvfCreateCommandBuffer(RenderCore::Get().GetDevice()); VkCommandBuffer cmd = kvfCreateCommandBuffer(RenderCore::Get().GetDevice());
kvfBeginCommandBuffer(cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); kvfBeginCommandBuffer(cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
TransitionLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, cmd);
kvfCopyBufferToImage(cmd, Image::Get(), staging_buffer.Get(), staging_buffer.GetOffset(), VK_IMAGE_ASPECT_COLOR_BIT, { width, height, 1 }); kvfCopyBufferToImage(cmd, Image::Get(), staging_buffer.Get(), staging_buffer.GetOffset(), VK_IMAGE_ASPECT_COLOR_BIT, { width, height, 1 });
vkEndCommandBuffer(cmd); vkEndCommandBuffer(cmd);
VkFence fence = kvfCreateFence(RenderCore::Get().GetDevice()); VkFence fence = kvfCreateFence(RenderCore::Get().GetDevice());
@@ -104,13 +105,26 @@ namespace mlx
kvfDestroyFence(RenderCore::Get().GetDevice(), fence); kvfDestroyFence(RenderCore::Get().GetDevice(), fence);
staging_buffer.Destroy(); staging_buffer.Destroy();
} }
if(!pixels) TransitionLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
TransitionLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
else
TransitionLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
} }
void SetPixel(int x, int y, std::uint32_t color) noexcept;
int GetPixel(int x, int y) noexcept;
void Update(VkCommandBuffer cmd) const;
~Texture() override { Destroy(); } ~Texture() override { Destroy(); }
private:
void OpenCPUBuffer();
private:
std::vector<std::uint32_t> m_cpu_buffer;
std::optional<GPUBuffer> m_staging_buffer;
bool m_has_been_modified = false;
}; };
Texture* StbTextureLoad(const std::filesystem::path& file, int* w, int* h);
} }
#endif #endif

View File

@@ -14,7 +14,7 @@ namespace mlx
{ {
}, "__Application" }); }, "__Application" });
m_fps.init(); m_fps.Init();
SDLManager::Get().Init(); SDLManager::Get().Init();
} }
@@ -26,7 +26,6 @@ namespace mlx
{ {
if(!m_fps.Update()) if(!m_fps.Update())
continue; continue;
m_in.Update();
if(f_loop_hook) if(f_loop_hook)
f_loop_hook(p_param); f_loop_hook(p_param);
@@ -37,27 +36,15 @@ namespace mlx
gs->Render(); gs->Render();
} }
} }
RenderCore::Get().WaitDeviceIdle();
RenderCore::Get().GetSingleTimeCmdManager().UpdateSingleTimesCmdBuffersSubmitState();
for(auto& gs : m_graphics)
{
if(!gs)
continue;
for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
gs->GetRenderer().GetCmdBuffer(i).WaitForExecution();
}
} }
void* Application::NewTexture(int w, int h) void* Application::NewTexture(int w, int h)
{ {
MLX_PROFILE_FUNCTION(); MLX_PROFILE_FUNCTION();
Texture* texture = new Texture; Texture* texture;
#ifdef DEBUG try { texture = new Texture({}, w, h); }
texture->Create(nullptr, w, h, VK_FORMAT_R8G8B8A8_UNORM, "__mlx_unamed_user_texture"); catch(...) { return NULL; }
#else
texture->Create(nullptr, w, h, VK_FORMAT_R8G8B8A8_UNORM, nullptr);
#endif
m_image_registry.RegisterTexture(texture); m_image_registry.RegisterTexture(texture);
return texture; return texture;
} }
@@ -66,6 +53,8 @@ namespace mlx
{ {
MLX_PROFILE_FUNCTION(); MLX_PROFILE_FUNCTION();
Texture* texture = StbTextureLoad(file, w, h); Texture* texture = StbTextureLoad(file, w, h);
if(texture == nullptr)
return NULL; // NULL for C compatibility
m_image_registry.RegisterTexture(texture); m_image_registry.RegisterTexture(texture);
return texture; return texture;
} }
@@ -74,7 +63,7 @@ namespace mlx
{ {
MLX_PROFILE_FUNCTION(); MLX_PROFILE_FUNCTION();
RenderCore::Get().WaitDeviceIdle(); // TODO : synchronize with another method than waiting for GPU to be idle RenderCore::Get().WaitDeviceIdle(); // TODO : synchronize with another method than waiting for GPU to be idle
if(!m_image_registry.Find(ptr)) if(!m_image_registry.IsTextureKnown(static_cast<Texture*>(ptr)))
{ {
Error("invalid image ptr"); Error("invalid image ptr");
return; return;
@@ -85,10 +74,10 @@ namespace mlx
Error("trying to destroy a texture that has already been destroyed"); Error("trying to destroy a texture that has already been destroyed");
else else
texture->Destroy(); texture->Destroy();
for(auto& gs : _graphics) for(auto& gs : m_graphics)
{ {
if(gs) if(gs)
gs->TryEraseTextureFromManager(texture); gs->TryEraseSpritesInScene(texture);
} }
m_image_registry.UnregisterTexture(texture); m_image_registry.UnregisterTexture(texture);
delete texture; delete texture;
@@ -96,8 +85,6 @@ namespace mlx
Application::~Application() Application::~Application()
{ {
TextLibrary::Get().ClearLibrary();
FontLibrary::Get().ClearLibrary();
SDLManager::Get().Shutdown(); SDLManager::Get().Shutdown();
} }
} }

View File

@@ -1,7 +1,7 @@
#include <PreCompiled.h> #include <PreCompiled.h>
#include <Core/Application.h> #include <Core/Application.h>
#include <Renderer/Core/RenderCore.h> #include <Renderer/RenderCore.h>
#include <mlx.h> #include <mlx.h>
#include <Core/Memory.h> #include <Core/Memory.h>
@@ -18,7 +18,7 @@ extern "C"
{ {
if(__mlx_ptr != nullptr) if(__mlx_ptr != nullptr)
{ {
Error("MLX cannot be initialized multiple times"); mlx::Error("MLX cannot be initialized multiple times");
return nullptr; return nullptr;
} }
mlx::MemManager::Get(); // just to initialize the C garbage collector mlx::MemManager::Get(); // just to initialize the C garbage collector

View File

@@ -64,7 +64,7 @@ namespace mlx
RenderCore::Get().WaitDeviceIdle(); RenderCore::Get().WaitDeviceIdle();
p_scene.reset(); p_scene.reset();
m_scene_renderer.Destroy(); m_scene_renderer.Destroy();
m_renderer->Destroy(); m_renderer.Destroy();
if(p_window) if(p_window)
p_window->Destroy(); p_window->Destroy();
} }

View File

@@ -12,10 +12,31 @@ namespace mlx
m_depth.Init(m_descriptor.renderer->GetSwapchainImages().back().GetWidth(), m_descriptor.renderer->GetSwapchainImages().back().GetHeight()); m_depth.Init(m_descriptor.renderer->GetSwapchainImages().back().GetWidth(), m_descriptor.renderer->GetSwapchainImages().back().GetHeight());
} }
Sprite& Scene::CreateSprite(std::shared_ptr<Texture> texture) noexcept Sprite& Scene::CreateSprite(NonOwningPtr<Texture> texture) noexcept
{ {
std::shared_ptr<Sprite> sprite = std::make_shared<Sprite>(texture); std::shared_ptr<Sprite> sprite = std::make_shared<Sprite>(texture);
m_sprites.push_back(sprite); m_sprites.push_back(sprite);
return *sprite; return *sprite;
} }
NonOwningPtr<Sprite> Scene::GetSpriteFromTextureAndPosition(NonOwningPtr<Texture> texture, const Vec2f& position) const
{
auto it = std::find_if(m_sprites.begin(), m_sprites.end(), [texture, position](const Sprite& sprite)
{
return sprite.GetPosition().x == position.x && sprite.GetPosition().y == position.y && sprite.GetTexture() == texture;
});
return (it != m_sprites.end() ? &(*it) : nullptr);
}
void Scene::TryEraseSpriteFromTexture(NonOwningPtr<Texture> texture)
{
do
{
auto it = std::find_if(m_sprites.begin(), m_sprites.end(), [texture, position](const Sprite& sprite)
{
return sprite.GetPosition().x == position.x && sprite.GetPosition().y == position.y && sprite.GetTexture() == texture;
});
m_sprites.erase(it);
} while(it != m_sprites.end());
}
} }

View File

@@ -35,7 +35,7 @@ namespace mlx
return mesh; return mesh;
} }
Sprite::Sprite(std::shared_ptr<Texture> texture) Sprite::Sprite(NonOwningPtr<Texture> texture)
{ {
Verify((bool)texture, "Sprite: invalid texture"); Verify((bool)texture, "Sprite: invalid texture");
p_mesh = CreateQuad(0, 0, texture->GetWidth(), texture->GetHeight()); p_mesh = CreateQuad(0, 0, texture->GetWidth(), texture->GetHeight());

View File

@@ -4,22 +4,4 @@
namespace mlx namespace mlx
{ {
void Input::update()
{
MLX_PROFILE_FUNCTION();
_xRel = 0;
_yRel = 0;
glfwPollEvents();
static int i = 0;
i++;
if(i >= 500)
{
auto& hooks = _events_hooks[0];
auto& win_hook = hooks[MLX_WINDOW_EVENT];
if(win_hook.hook)
win_hook.hook(0, win_hook.param);
}
}
} }

View File

@@ -50,7 +50,10 @@ namespace mlx
return; return;
bool is_single_time_cmd_buffer = (cmd == VK_NULL_HANDLE); bool is_single_time_cmd_buffer = (cmd == VK_NULL_HANDLE);
if(is_single_time_cmd_buffer) if(is_single_time_cmd_buffer)
{
cmd = kvfCreateCommandBuffer(RenderCore::Get().GetDevice()); cmd = kvfCreateCommandBuffer(RenderCore::Get().GetDevice());
kvfBeginCommandBuffer(cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
}
KvfImageType kvf_type = KVF_IMAGE_OTHER; KvfImageType kvf_type = KVF_IMAGE_OTHER;
switch(m_type) switch(m_type)
{ {
@@ -61,6 +64,13 @@ namespace mlx
} }
kvfTransitionImageLayout(RenderCore::Get().GetDevice(), m_image, kvf_type, cmd, m_format, m_layout, new_layout, is_single_time_cmd_buffer); kvfTransitionImageLayout(RenderCore::Get().GetDevice(), m_image, kvf_type, cmd, m_format, m_layout, new_layout, is_single_time_cmd_buffer);
m_layout = new_layout; m_layout = new_layout;
if(is_single_time_cmd_buffer)
{
vkEndCommandBuffer(cmd);
VkFence fence = kvfCreateFence(RenderCore::Get().GetDevice());
kvfSubmitSingleTimeCommandBuffer(RenderCore::Get().GetDevice(), cmd, KVF_GRAPHICS_QUEUE, fence);
kvfDestroyFence(RenderCore::Get().GetDevice(), fence);
}
} }
void Image::Clear(VkCommandBuffer cmd, Vec4f color) void Image::Clear(VkCommandBuffer cmd, Vec4f color)
@@ -112,4 +122,105 @@ namespace mlx
RenderCore::Get().GetAllocator().DestroyImage(m_allocation, m_image); RenderCore::Get().GetAllocator().DestroyImage(m_allocation, m_image);
m_image = VK_NULL_HANDLE; m_image = VK_NULL_HANDLE;
} }
void Texture::SetPixel(int x, int y, std::uint32_t color) noexcept
{
MLX_PROFILE_FUNCTION();
if(x < 0 || y < 0 || static_cast<std::uint32_t>(x) > m_width || static_cast<std::uint32_t>(y) > m_height)
return;
if(!m_staging_buffer.has_value())
OpenCPUBuffer();
m_cpu_buffer[(y * m_width) + x] = color;
m_has_been_modified = true;
}
int GetPixel(int x, int y) noexcept
{
MLX_PROFILE_FUNCTION();
if(x < 0 || y < 0 || static_cast<std::uint32_t>(x) > getWidth() || static_cast<std::uint32_t>(y) > getHeight())
return 0;
if(!m_staging_buffer.has_value())
OpenCPUBuffer();
std::uint32_t color = m_cpu_buffer[(y * m_width) + x];
std::uint8_t* bytes = reinterpret_cast<std::uint8_t*>(&color);
std::uint8_t tmp = bytes[0];
bytes[0] = bytes[2];
bytes[2] = tmp;
return *reinterpret_cast<int*>(bytes);
}
void Update(VkCommandBuffer cmd) const
{
if(!m_has_been_modified)
return;
std::memcpy(m_staging_buffer.GetMap(), m_cpu_buffer.data(), m_cpu_buffer.size() * kvfGetFormatSize(m_format));
VkImageLayout old_layout = m_layout;
VkCommandBuffer cmd = kvfCreateCommandBuffer(RenderCore::Get().GetDevice());
kvfBeginCommandBuffer(cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
TransitionLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, cmd);
kvfCopyBufferToImage(cmd, Image::Get(), staging_buffer.Get(), staging_buffer.GetOffset(), VK_IMAGE_ASPECT_COLOR_BIT, { width, height, 1 });
TransitionLayout(old_layout, cmd);
vkEndCommandBuffer(cmd);
VkFence fence = kvfCreateFence(RenderCore::Get().GetDevice());
kvfSubmitSingleTimeCommandBuffer(RenderCore::Get().GetDevice(), cmd, KVF_GRAPHICS_QUEUE, fence);
kvfDestroyFence(RenderCore::Get().GetDevice(), fence);
m_has_been_modified = false;
}
void Texture::OpenCPUBuffer()
{
MLX_PROFILE_FUNCTION();
if(m_staging_buffer.has_value())
return;
DebugLog("Texture : enabling CPU mapping");
m_staging_buffer.emplace();
std::size_t size = m_width * m_height * kvfGetFormatSize(m_format);
m_staging_buffer->Init(BufferType::Staging, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, {});
VkImageLayout old_layout = m_layout;
VkCommandBuffer cmd = kvfCreateCommandBuffer(RenderCore::Get().GetDevice());
kvfBeginCommandBuffer(cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
TransitionLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, cmd);
kvfImageToBuffer(cmd, m_image, m_staging_buffer.Get(), m_staging_buffer.GetOffset(), VK_IMAGE_ASPECT_COLOR_BIT, { m_width, m_height, 1 });
TransitionLayout(old_layout, cmd);
vkEndCommandBuffer(cmd);
VkFence fence = kvfCreateFence(RenderCore::Get().GetDevice());
kvfSubmitSingleTimeCommandBuffer(RenderCore::Get().GetDevice(), cmd, KVF_GRAPHICS_QUEUE, fence);
kvfDestroyFence(RenderCore::Get().GetDevice(), fence);
m_cpu_buffer.resize(m_width * m_height);
std::memcpy(m_cpu_buffer.data(), m_staging_buffer.GetMap(), m_cpu_buffer.size());
}
Texture* StbTextureLoad(const std::filesystem::path& file, int* w, int* h)
{
MLX_PROFILE_FUNCTION();
std::string filename = file.string();
if(!std::filesystem::exists(file))
{
Error("Image : file not found %", file);
return nullptr;
}
if(stbi_is_hdr(filename.c_str()))
{
Error("Texture : unsupported image format %", file);
return nullptr;
}
int dummy_w;
int dummy_h;
int channels;
std::uint8_t* data = stbi_load(filename.c_str(), (w == nullptr ? &dummy_w : w), (h == nullptr ? &dummy_h : h), &channels, 4);
CPUBuffer buffer((w == nullptr ? dummy_w : *w) * (h == nullptr ? dummy_h : *h) * 4);
std::memcpy(buffer.GetData(), data, buffer.GetSize());
Texture* texture;
try { texture = new Texture(buffer, (w == nullptr ? dummy_w : *w), (h == nullptr ? dummy_h : *h)); }
catch(...) { return NULL; }
stbi_image_free(data);
return texture;
}
} }

View File

@@ -102,6 +102,8 @@ namespace mlx
sprite_data.color = sprite->GetColor(); sprite_data.color = sprite->GetColor();
if(!sprite->IsSetInit()) if(!sprite->IsSetInit())
sprite->UpdateDescriptorSet(*p_texture_set); sprite->UpdateDescriptorSet(*p_texture_set);
Verify((bool)sprite->GetTexture(), "a sprite has no texture attached");
sprite->GetTexture()->Update(cmd);
sprite->Bind(frame_index, cmd); sprite->Bind(frame_index, cmd);
std::array<VkDescriptorSet, 2> sets = { p_viewer_data_set->GetSet(frame_index), sprite->GetSet(frame_index) }; std::array<VkDescriptorSet, 2> sets = { p_viewer_data_set->GetSet(frame_index), sprite->GetSet(frame_index) };
vkCmdBindDescriptorSets(cmd, m_pipeline.GetPipelineBindPoint(), m_pipeline.GetPipelineLayout(), 0, sets.size(), sets.data(), 0, nullptr); vkCmdBindDescriptorSets(cmd, m_pipeline.GetPipelineBindPoint(), m_pipeline.GetPipelineLayout(), 0, sets.size(), sets.data(), 0, nullptr);

180
third_party/kvf.h vendored
View File

@@ -92,7 +92,8 @@ void kvfAddLayer(const char* layer);
VkInstance kvfCreateInstance(const char** extensionsEnabled, uint32_t extensionsCount); VkInstance kvfCreateInstance(const char** extensionsEnabled, uint32_t extensionsCount);
void kvfDestroyInstance(VkInstance instance); void kvfDestroyInstance(VkInstance instance);
VkPhysicalDevice kvfPickFirstPhysicalDevice(VkInstance instance); // If surfaces given to theses functions are VK_NULL_HANDLE no present queues will be searched and thus kvfQueuePresentKHR will not work
VkPhysicalDevice kvfPickFirstPhysicalDevice(VkInstance instance, VkSurfaceKHR surface);
VkPhysicalDevice kvfPickGoodDefaultPhysicalDevice(VkInstance instance, VkSurfaceKHR surface); VkPhysicalDevice kvfPickGoodDefaultPhysicalDevice(VkInstance instance, VkSurfaceKHR surface);
VkPhysicalDevice kvfPickGoodPhysicalDevice(VkInstance instance, VkSurfaceKHR surface, const char** deviceExtensions, uint32_t deviceExtensionsCount); VkPhysicalDevice kvfPickGoodPhysicalDevice(VkInstance instance, VkSurfaceKHR surface, const char** deviceExtensions, uint32_t deviceExtensionsCount);
@@ -101,7 +102,7 @@ uint32_t kvfGetDeviceQueueFamily(VkDevice device, KvfQueueType queue);
bool kvfQueuePresentKHR(VkDevice device, VkSemaphore wait, VkSwapchainKHR swapchain, uint32_t image_index); // return false when the swapchain must be recreated bool kvfQueuePresentKHR(VkDevice device, VkSemaphore wait, VkSwapchainKHR swapchain, uint32_t image_index); // return false when the swapchain must be recreated
VkDevice kvfCreateDefaultDevice(VkPhysicalDevice physical); VkDevice kvfCreateDefaultDevice(VkPhysicalDevice physical);
VkDevice kvfCreateDevice(VkPhysicalDevice physical, const char** extensions, uint32_t extensions_count); VkDevice kvfCreateDevice(VkPhysicalDevice physical, const char** extensions, uint32_t extensions_count, VkPhysicalDeviceFeatures* features);
void kvfDestroyDevice(VkDevice device); void kvfDestroyDevice(VkDevice device);
VkFence kvfCreateFence(VkDevice device); VkFence kvfCreateFence(VkDevice device);
@@ -118,12 +119,12 @@ uint32_t kvfGetSwapchainMinImagesCount(VkSwapchainKHR swapchain);
VkExtent2D kvfGetSwapchainImagesSize(VkSwapchainKHR swapchain); VkExtent2D kvfGetSwapchainImagesSize(VkSwapchainKHR swapchain);
void kvfDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain); void kvfDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain);
VkImage kvfCreateImage(VkDevice device, uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage); VkImage kvfCreateImage(VkDevice device, uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, KvfImageType type);
void kvfImageBufferToBuffer(VkCommandBuffer cmd, VkBuffer dst, VkImage src, size_t size); void kvfImageToBuffer(VkCommandBuffer cmd, VkBuffer dst, VkImage src, size_t size);
void kvfDestroyImage(VkDevice device, VkImage image); void kvfDestroyImage(VkDevice device, VkImage image);
VkImageView kvfCreateImageView(VkDevice device, VkImage image, VkFormat format, VkImageViewType type, VkImageAspectFlags aspect); VkImageView kvfCreateImageView(VkDevice device, VkImage image, VkFormat format, VkImageViewType type, VkImageAspectFlags aspect, int layer_count);
void kvfDestroyImageView(VkDevice device, VkImageView image_view); void kvfDestroyImageView(VkDevice device, VkImageView image_view);
void kvfTransitionImageLayout(VkDevice device, VkImage image, VkCommandBuffer cmd, VkFormat format, VkImageLayout old_layout, VkImageLayout new_layout, bool is_single_time_cmd_buffer); void kvfTransitionImageLayout(VkDevice device, VkImage image, KvfImageType type, VkCommandBuffer cmd, VkFormat format, VkImageLayout old_layout, VkImageLayout new_layout, bool is_single_time_cmd_buffer);
VkSampler kvfCreateSampler(VkDevice device, VkFilter filters, VkSamplerAddressMode address_modes, VkSamplerMipmapMode mipmap_mode); VkSampler kvfCreateSampler(VkDevice device, VkFilter filters, VkSamplerAddressMode address_modes, VkSamplerMipmapMode mipmap_mode);
void kvfDestroySampler(VkDevice device, VkSampler sampler); void kvfDestroySampler(VkDevice device, VkSampler sampler);
@@ -143,10 +144,11 @@ void kvfEndCommandBuffer(VkCommandBuffer buffer);
void kvfSubmitCommandBuffer(VkDevice device, VkCommandBuffer buffer, KvfQueueType queue, VkSemaphore signal, VkSemaphore wait, VkFence fence, VkPipelineStageFlags* stages); void kvfSubmitCommandBuffer(VkDevice device, VkCommandBuffer buffer, KvfQueueType queue, VkSemaphore signal, VkSemaphore wait, VkFence fence, VkPipelineStageFlags* stages);
void kvfSubmitSingleTimeCommandBuffer(VkDevice device, VkCommandBuffer buffer, KvfQueueType queue, VkFence fence); void kvfSubmitSingleTimeCommandBuffer(VkDevice device, VkCommandBuffer buffer, KvfQueueType queue, VkFence fence);
VkAttachmentDescription kvfBuildAttachmentDescription(KvfImageType type, VkFormat format, VkImageLayout initial, VkImageLayout final, bool clear); VkAttachmentDescription kvfBuildAttachmentDescription(KvfImageType type, VkFormat format, VkImageLayout initial, VkImageLayout final, bool clear, VkSampleCountFlagBits samples);
VkAttachmentDescription kvfBuildSwapchainAttachmentDescription(VkSwapchainKHR swapchain, bool clear); VkAttachmentDescription kvfBuildSwapchainAttachmentDescription(VkSwapchainKHR swapchain, bool clear);
VkRenderPass kvfCreateRenderPass(VkDevice device, VkAttachmentDescription* attachments, size_t attachments_count, VkPipelineBindPoint bind_point); VkRenderPass kvfCreateRenderPass(VkDevice device, VkAttachmentDescription* attachments, size_t attachments_count, VkPipelineBindPoint bind_point);
VkRenderPass kvfCreateRenderPassWithSubpassDependencies(VkDevice device, VkAttachmentDescription* attachments, size_t attachments_count, VkPipelineBindPoint bind_point, VkSubpassDependency* dependencies, size_t dependencies_count);
void kvfDestroyRenderPass(VkDevice device, VkRenderPass renderpass); void kvfDestroyRenderPass(VkDevice device, VkRenderPass renderpass);
void kvfBeginRenderPass(VkRenderPass pass, VkCommandBuffer cmd, VkFramebuffer framebuffer, VkExtent2D framebuffer_extent, VkClearValue* clears, size_t clears_count); void kvfBeginRenderPass(VkRenderPass pass, VkCommandBuffer cmd, VkFramebuffer framebuffer, VkExtent2D framebuffer_extent, VkClearValue* clears, size_t clears_count);
@@ -185,6 +187,8 @@ void kvfGPipelineBuilderReset(KvfGraphicsPipelineBuilder* builder);
void kvfGPipelineBuilderSetInputTopology(KvfGraphicsPipelineBuilder* builder, VkPrimitiveTopology topology); void kvfGPipelineBuilderSetInputTopology(KvfGraphicsPipelineBuilder* builder, VkPrimitiveTopology topology);
void kvfGPipelineBuilderSetPolygonMode(KvfGraphicsPipelineBuilder* builder, VkPolygonMode polygon, float line_width); void kvfGPipelineBuilderSetPolygonMode(KvfGraphicsPipelineBuilder* builder, VkPolygonMode polygon, float line_width);
void kvfGPipelineBuilderSetCullMode(KvfGraphicsPipelineBuilder* builder, VkCullModeFlags cull, VkFrontFace face); void kvfGPipelineBuilderSetCullMode(KvfGraphicsPipelineBuilder* builder, VkCullModeFlags cull, VkFrontFace face);
void kvfGPipelineBuilderSetMultisampling(KvfGraphicsPipelineBuilder* builder, VkSampleCountFlagBits count);
void kvfGPipelineBuilderSetMultisamplingShading(KvfGraphicsPipelineBuilder* builder, VkSampleCountFlagBits count, float min_sampling_shading);
void kvfGPipelineBuilderDisableBlending(KvfGraphicsPipelineBuilder* builder); void kvfGPipelineBuilderDisableBlending(KvfGraphicsPipelineBuilder* builder);
void kvfGPipelineBuilderEnableAdditiveBlending(KvfGraphicsPipelineBuilder* builder); void kvfGPipelineBuilderEnableAdditiveBlending(KvfGraphicsPipelineBuilder* builder);
void kvfGPipelineBuilderEnableAlphaBlending(KvfGraphicsPipelineBuilder* builder); void kvfGPipelineBuilderEnableAlphaBlending(KvfGraphicsPipelineBuilder* builder);
@@ -197,6 +201,8 @@ void kvfGPipelineBuilderResetShaderStages(KvfGraphicsPipelineBuilder* builder);
VkPipeline kvfCreateGraphicsPipeline(VkDevice device, VkPipelineLayout layout, KvfGraphicsPipelineBuilder* builder, VkRenderPass pass); VkPipeline kvfCreateGraphicsPipeline(VkDevice device, VkPipelineLayout layout, KvfGraphicsPipelineBuilder* builder, VkRenderPass pass);
void kvfDestroyPipeline(VkDevice device, VkPipeline pipeline); void kvfDestroyPipeline(VkDevice device, VkPipeline pipeline);
void kvfCheckVk(VkResult result);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
@@ -287,6 +293,7 @@ struct KvfGraphicsPipelineBuilder
VkPipelineRasterizationStateCreateInfo rasterization_state; VkPipelineRasterizationStateCreateInfo rasterization_state;
VkPipelineDepthStencilStateCreateInfo depth_stencil_state; VkPipelineDepthStencilStateCreateInfo depth_stencil_state;
VkPipelineColorBlendAttachmentState color_blend_attachment_state; VkPipelineColorBlendAttachmentState color_blend_attachment_state;
VkPipelineMultisampleStateCreateInfo multisampling;
size_t shader_stages_count; size_t shader_stages_count;
}; };
@@ -334,6 +341,11 @@ void __kvfCheckVk(VkResult result, const char* function)
#undef __kvfCheckVk #undef __kvfCheckVk
#define __kvfCheckVk(res) __kvfCheckVk(res, __FUNCTION__) #define __kvfCheckVk(res) __kvfCheckVk(res, __FUNCTION__)
void kvfCheckVk(VkResult result)
{
__kvfCheckVk(result);
}
void __kvfAddDeviceToArray(VkPhysicalDevice device, int32_t graphics_queue, int32_t present_queue) void __kvfAddDeviceToArray(VkPhysicalDevice device, int32_t graphics_queue, int32_t present_queue)
{ {
KVF_ASSERT(device != VK_NULL_HANDLE); KVF_ASSERT(device != VK_NULL_HANDLE);
@@ -518,7 +530,7 @@ void __kvfDestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer)
} }
} }
__KvfFramebuffer* __kvfGetKvfSwapchainFromVkFramebuffer(VkFramebuffer framebuffer) __KvfFramebuffer* __kvfGetKvfFramebufferFromVkFramebuffer(VkFramebuffer framebuffer)
{ {
KVF_ASSERT(framebuffer != VK_NULL_HANDLE); KVF_ASSERT(framebuffer != VK_NULL_HANDLE);
for(size_t i = 0; i < __kvf_internal_framebuffers_size; i++) for(size_t i = 0; i < __kvf_internal_framebuffers_size; i++)
@@ -1061,22 +1073,6 @@ void kvfDestroyInstance(VkInstance instance)
vkDestroyInstance(instance, NULL); vkDestroyInstance(instance, NULL);
} }
VkPhysicalDevice kvfPickFirstPhysicalDevice(VkInstance instance)
{
uint32_t device_count;
VkPhysicalDevice* devices = NULL;
VkPhysicalDevice chosen_one = VK_NULL_HANDLE;
KVF_ASSERT(instance != VK_NULL_HANDLE);
vkEnumeratePhysicalDevices(instance, &device_count, NULL);
devices = (VkPhysicalDevice*)KVF_MALLOC(sizeof(VkPhysicalDevice) * device_count + 1);
vkEnumeratePhysicalDevices(instance, &device_count, devices);
chosen_one = devices[0];
KVF_FREE(devices);
return chosen_one;
}
__KvfQueueFamilies __kvfFindQueueFamilies(VkPhysicalDevice physical, VkSurfaceKHR surface) __KvfQueueFamilies __kvfFindQueueFamilies(VkPhysicalDevice physical, VkSurfaceKHR surface)
{ {
__KvfQueueFamilies queues = { -1, -1, -1 }; __KvfQueueFamilies queues = { -1, -1, -1 };
@@ -1095,17 +1091,39 @@ __KvfQueueFamilies __kvfFindQueueFamilies(VkPhysicalDevice physical, VkSurfaceKH
if(queue_families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) if(queue_families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
queues.graphics = i; queues.graphics = i;
VkBool32 present_support = false; VkBool32 present_support = false;
vkGetPhysicalDeviceSurfaceSupportKHR(physical, i, surface, &present_support); if(surface != VK_NULL_HANDLE)
if(present_support) {
queues.present = i; vkGetPhysicalDeviceSurfaceSupportKHR(physical, i, surface, &present_support);
if(present_support)
if(queues.graphics != -1 && queues.present != -1 && queues.compute != -1) queues.present = i;
if(queues.graphics != -1 && queues.present != -1 && queues.compute != -1)
break;
}
else if(queues.graphics != -1 && queues.compute != -1)
break; break;
} }
KVF_FREE(queue_families); KVF_FREE(queue_families);
return queues; return queues;
} }
VkPhysicalDevice kvfPickFirstPhysicalDevice(VkInstance instance, VkSurfaceKHR surface)
{
uint32_t device_count;
VkPhysicalDevice* devices = NULL;
VkPhysicalDevice chosen_one = VK_NULL_HANDLE;
KVF_ASSERT(instance != VK_NULL_HANDLE);
vkEnumeratePhysicalDevices(instance, &device_count, NULL);
devices = (VkPhysicalDevice*)KVF_MALLOC(sizeof(VkPhysicalDevice) * device_count + 1);
vkEnumeratePhysicalDevices(instance, &device_count, devices);
chosen_one = devices[0];
KVF_FREE(devices);
__KvfQueueFamilies queues = __kvfFindQueueFamilies(chosen_one, surface);
__kvfAddDeviceToArray(chosen_one, queues.graphics, queues.present);
return chosen_one;
}
VkPhysicalDevice kvfPickGoodDefaultPhysicalDevice(VkInstance instance, VkSurfaceKHR surface) VkPhysicalDevice kvfPickGoodDefaultPhysicalDevice(VkInstance instance, VkSurfaceKHR surface)
{ {
const char* extensions[] = { VK_KHR_SWAPCHAIN_EXTENSION_NAME }; const char* extensions[] = { VK_KHR_SWAPCHAIN_EXTENSION_NAME };
@@ -1208,10 +1226,11 @@ VkPhysicalDevice kvfPickGoodPhysicalDevice(VkInstance instance, VkSurfaceKHR sur
VkDevice kvfCreateDefaultDevice(VkPhysicalDevice physical) VkDevice kvfCreateDefaultDevice(VkPhysicalDevice physical)
{ {
const char* extensions[] = { VK_KHR_SWAPCHAIN_EXTENSION_NAME }; const char* extensions[] = { VK_KHR_SWAPCHAIN_EXTENSION_NAME };
return kvfCreateDevice(physical, extensions, sizeof(extensions) / sizeof(extensions[0])); VkPhysicalDeviceFeatures device_features = { VK_FALSE };
return kvfCreateDevice(physical, extensions, sizeof(extensions) / sizeof(extensions[0]), &device_features);
} }
VkDevice kvfCreateDevice(VkPhysicalDevice physical, const char** extensions, uint32_t extensions_count) VkDevice kvfCreateDevice(VkPhysicalDevice physical, const char** extensions, uint32_t extensions_count, VkPhysicalDeviceFeatures* features)
{ {
const float queue_priority = 1.0f; const float queue_priority = 1.0f;
@@ -1235,13 +1254,11 @@ VkDevice kvfCreateDevice(VkPhysicalDevice physical, const char** extensions, uin
queue_create_info[1].flags = 0; queue_create_info[1].flags = 0;
queue_create_info[1].pNext = NULL; queue_create_info[1].pNext = NULL;
VkPhysicalDeviceFeatures device_features = { VK_FALSE };
VkDeviceCreateInfo createInfo; VkDeviceCreateInfo createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
createInfo.queueCreateInfoCount = (kvfdevice->queues.graphics == kvfdevice->queues.present ? 1 : 2); createInfo.queueCreateInfoCount = (kvfdevice->queues.graphics == kvfdevice->queues.present ? 1 : 2);
createInfo.pQueueCreateInfos = queue_create_info; createInfo.pQueueCreateInfos = queue_create_info;
createInfo.pEnabledFeatures = &device_features; createInfo.pEnabledFeatures = features;
createInfo.enabledExtensionCount = extensions_count; createInfo.enabledExtensionCount = extensions_count;
createInfo.ppEnabledExtensionNames = extensions; createInfo.ppEnabledExtensionNames = extensions;
createInfo.enabledLayerCount = 0; createInfo.enabledLayerCount = 0;
@@ -1502,7 +1519,7 @@ void kvfDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain)
__kvfDestroySwapchain(device, swapchain); __kvfDestroySwapchain(device, swapchain);
} }
VkImage kvfCreateImage(VkDevice device, uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage) VkImage kvfCreateImage(VkDevice device, uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, KvfImageType type)
{ {
KVF_ASSERT(device != VK_NULL_HANDLE); KVF_ASSERT(device != VK_NULL_HANDLE);
VkImageCreateInfo image_info = {}; VkImageCreateInfo image_info = {};
@@ -1519,11 +1536,37 @@ VkImage kvfCreateImage(VkDevice device, uint32_t width, uint32_t height, VkForma
image_info.usage = usage; image_info.usage = usage;
image_info.samples = VK_SAMPLE_COUNT_1_BIT; image_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
switch(type)
{
case KVF_IMAGE_CUBE: image_info.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; image_info.arrayLayers = 6; break;
default: break;
}
VkImage image; VkImage image;
__kvfCheckVk(vkCreateImage(device, &image_info, NULL, &image)); __kvfCheckVk(vkCreateImage(device, &image_info, NULL, &image));
return image; return image;
} }
void kvfImageToBuffer(VkCommandBuffer cmd, VkBuffer dst, VkImage src, size_t buffer_offset, VkImageAspectFlagBits aspect, VkExtent3D extent)
{
KVF_ASSERT(cmd != VK_NULL_HANDLE);
KVF_ASSERT(dst != VK_NULL_HANDLE);
KVF_ASSERT(src != VK_NULL_HANDLE);
VkOffset3D offset = { 0, 0, 0 };
VkBufferImageCopy region = {};
region.bufferOffset = buffer_offset;
region.bufferRowLength = 0;
region.bufferImageHeight = 0;
region.imageSubresource.aspectMask = aspect;
region.imageSubresource.mipLevel = 0;
region.imageSubresource.baseArrayLayer = 0;
region.imageSubresource.layerCount = 1;
region.imageOffset = offset;
region.imageExtent = extent;
vkCmdCopyImageToBuffer(cmd, src, dst, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 1, &region);
}
void kvfDestroyImage(VkDevice device, VkImage image) void kvfDestroyImage(VkDevice device, VkImage image)
{ {
if(image == VK_NULL_HANDLE) if(image == VK_NULL_HANDLE)
@@ -1532,7 +1575,7 @@ void kvfDestroyImage(VkDevice device, VkImage image)
vkDestroyImage(device, image, NULL); vkDestroyImage(device, image, NULL);
} }
VkImageView kvfCreateImageView(VkDevice device, VkImage image, VkFormat format, VkImageViewType type, VkImageAspectFlags aspect) VkImageView kvfCreateImageView(VkDevice device, VkImage image, VkFormat format, VkImageViewType type, VkImageAspectFlags aspect, int layer_count)
{ {
KVF_ASSERT(device != VK_NULL_HANDLE); KVF_ASSERT(device != VK_NULL_HANDLE);
VkImageViewCreateInfo create_info = {}; VkImageViewCreateInfo create_info = {};
@@ -1548,7 +1591,7 @@ VkImageView kvfCreateImageView(VkDevice device, VkImage image, VkFormat format,
create_info.subresourceRange.baseMipLevel = 0; create_info.subresourceRange.baseMipLevel = 0;
create_info.subresourceRange.levelCount = 1; create_info.subresourceRange.levelCount = 1;
create_info.subresourceRange.baseArrayLayer = 0; create_info.subresourceRange.baseArrayLayer = 0;
create_info.subresourceRange.layerCount = 1; create_info.subresourceRange.layerCount = layer_count;
VkImageView view; VkImageView view;
__kvfCheckVk(vkCreateImageView(device, &create_info, NULL, &view)); __kvfCheckVk(vkCreateImageView(device, &create_info, NULL, &view));
return view; return view;
@@ -1561,7 +1604,7 @@ void kvfDestroyImageView(VkDevice device, VkImageView image_view)
vkDestroyImageView(device, image_view, NULL); vkDestroyImageView(device, image_view, NULL);
} }
void kvfTransitionImageLayout(VkDevice device, VkImage image, VkCommandBuffer cmd, VkFormat format, VkImageLayout old_layout, VkImageLayout new_layout, bool is_single_time_cmd_buffer) void kvfTransitionImageLayout(VkDevice device, VkImage image, KvfImageType type, VkCommandBuffer cmd, VkFormat format, VkImageLayout old_layout, VkImageLayout new_layout, bool is_single_time_cmd_buffer)
{ {
KVF_ASSERT(device != VK_NULL_HANDLE); KVF_ASSERT(device != VK_NULL_HANDLE);
@@ -1582,7 +1625,7 @@ void kvfTransitionImageLayout(VkDevice device, VkImage image, VkCommandBuffer cm
barrier.subresourceRange.baseMipLevel = 0; barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1; barrier.subresourceRange.levelCount = 1;
barrier.subresourceRange.baseArrayLayer = 0; barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 1; barrier.subresourceRange.layerCount = (type == KVF_IMAGE_CUBE ? 6 : 1);
barrier.srcAccessMask = kvfLayoutToAccessMask(old_layout, false); barrier.srcAccessMask = kvfLayoutToAccessMask(old_layout, false);
barrier.dstAccessMask = kvfLayoutToAccessMask(new_layout, true); barrier.dstAccessMask = kvfLayoutToAccessMask(new_layout, true);
if(kvfIsStencilFormat(format)) if(kvfIsStencilFormat(format))
@@ -1590,7 +1633,7 @@ void kvfTransitionImageLayout(VkDevice device, VkImage image, VkCommandBuffer cm
VkPipelineStageFlags source_stage = 0; VkPipelineStageFlags source_stage = 0;
if(barrier.oldLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) if(barrier.oldLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR)
source_stage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; source_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
else if(barrier.srcAccessMask != 0) else if(barrier.srcAccessMask != 0)
source_stage = kvfAccessFlagsToPipelineStage(barrier.srcAccessMask, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); source_stage = kvfAccessFlagsToPipelineStage(barrier.srcAccessMask, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
else else
@@ -1598,7 +1641,7 @@ void kvfTransitionImageLayout(VkDevice device, VkImage image, VkCommandBuffer cm
VkPipelineStageFlags destination_stage = 0; VkPipelineStageFlags destination_stage = 0;
if(barrier.newLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) if(barrier.newLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR)
destination_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; destination_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
else if(barrier.dstAccessMask != 0) else if(barrier.dstAccessMask != 0)
destination_stage = kvfAccessFlagsToPipelineStage(barrier.dstAccessMask, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); destination_stage = kvfAccessFlagsToPipelineStage(barrier.dstAccessMask, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
else else
@@ -1714,7 +1757,7 @@ VkFramebuffer kvfCreateFramebuffer(VkDevice device, VkRenderPass render_pass, Vk
VkExtent2D kvfGetFramebufferSize(VkFramebuffer buffer) VkExtent2D kvfGetFramebufferSize(VkFramebuffer buffer)
{ {
__KvfFramebuffer* kvf_framebuffer = __kvfGetKvfSwapchainFromVkFramebuffer(buffer); __KvfFramebuffer* kvf_framebuffer = __kvfGetKvfFramebufferFromVkFramebuffer(buffer);
KVF_ASSERT(kvf_framebuffer != NULL); KVF_ASSERT(kvf_framebuffer != NULL);
return kvf_framebuffer->extent; return kvf_framebuffer->extent;
} }
@@ -1805,7 +1848,7 @@ void kvfSubmitSingleTimeCommandBuffer(VkDevice device, VkCommandBuffer buffer, K
vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX); vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX);
} }
VkAttachmentDescription kvfBuildAttachmentDescription(KvfImageType type, VkFormat format, VkImageLayout initial, VkImageLayout final, bool clear) VkAttachmentDescription kvfBuildAttachmentDescription(KvfImageType type, VkFormat format, VkImageLayout initial, VkImageLayout final, bool clear, VkSampleCountFlagBits samples)
{ {
VkAttachmentDescription attachment = {}; VkAttachmentDescription attachment = {};
@@ -1833,12 +1876,23 @@ VkAttachmentDescription kvfBuildAttachmentDescription(KvfImageType type, VkForma
} }
else else
{ {
attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; if(samples != VK_SAMPLE_COUNT_1_BIT)
attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; {
attachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
}
else
{
attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
}
} }
attachment.samples = VK_SAMPLE_COUNT_1_BIT; attachment.samples = samples;
attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; if(samples != VK_SAMPLE_COUNT_1_BIT)
attachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
else
attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachment.flags = 0; attachment.flags = 0;
@@ -1850,13 +1904,17 @@ VkAttachmentDescription kvfBuildSwapchainAttachmentDescription(VkSwapchainKHR sw
__KvfSwapchain* kvf_swapchain = __kvfGetKvfSwapchainFromVkSwapchainKHR(swapchain); __KvfSwapchain* kvf_swapchain = __kvfGetKvfSwapchainFromVkSwapchainKHR(swapchain);
KVF_ASSERT(kvf_swapchain != NULL); KVF_ASSERT(kvf_swapchain != NULL);
KVF_ASSERT(kvf_swapchain->images_count != 0); KVF_ASSERT(kvf_swapchain->images_count != 0);
return kvfBuildAttachmentDescription(KVF_IMAGE_COLOR, kvf_swapchain->images_format, VK_IMAGE_LAYOUT_UNDEFINED,VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, clear); return kvfBuildAttachmentDescription(KVF_IMAGE_COLOR, kvf_swapchain->images_format, VK_IMAGE_LAYOUT_UNDEFINED,VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, clear, VK_SAMPLE_COUNT_1_BIT);
} }
VkRenderPass kvfCreateRenderPass(VkDevice device, VkAttachmentDescription* attachments, size_t attachments_count, VkPipelineBindPoint bind_point) VkRenderPass kvfCreateRenderPass(VkDevice device, VkAttachmentDescription* attachments, size_t attachments_count, VkPipelineBindPoint bind_point)
{ {
KVF_ASSERT(device != VK_NULL_HANDLE); KVF_ASSERT(device != VK_NULL_HANDLE);
return kvfCreateRenderPassWithSubpassDependencies(device, attachments, attachments_count, bind_point, NULL, 0);
}
VkRenderPass kvfCreateRenderPassWithSubpassDependencies(VkDevice device, VkAttachmentDescription* attachments, size_t attachments_count, VkPipelineBindPoint bind_point, VkSubpassDependency* dependencies, size_t dependencies_count)
{
size_t color_attachment_count = 0; size_t color_attachment_count = 0;
size_t depth_attachment_count = 0; size_t depth_attachment_count = 0;
@@ -1911,8 +1969,8 @@ VkRenderPass kvfCreateRenderPass(VkDevice device, VkAttachmentDescription* attac
renderpass_create_info.pAttachments = attachments; renderpass_create_info.pAttachments = attachments;
renderpass_create_info.subpassCount = 1; renderpass_create_info.subpassCount = 1;
renderpass_create_info.pSubpasses = &subpass; renderpass_create_info.pSubpasses = &subpass;
renderpass_create_info.dependencyCount = 0; renderpass_create_info.dependencyCount = dependencies_count;
renderpass_create_info.pDependencies = NULL; renderpass_create_info.pDependencies = dependencies;
VkRenderPass render_pass = VK_NULL_HANDLE; VkRenderPass render_pass = VK_NULL_HANDLE;
__kvfCheckVk(vkCreateRenderPass(device, &renderpass_create_info, NULL, &render_pass)); __kvfCheckVk(vkCreateRenderPass(device, &renderpass_create_info, NULL, &render_pass));
@@ -2144,6 +2202,7 @@ void kvfGPipelineBuilderReset(KvfGraphicsPipelineBuilder* builder)
builder->tessellation_state.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; builder->tessellation_state.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
builder->rasterization_state.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; builder->rasterization_state.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
builder->depth_stencil_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; builder->depth_stencil_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
builder->multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
} }
void kvfGPipelineBuilderSetInputTopology(KvfGraphicsPipelineBuilder* builder, VkPrimitiveTopology topology) void kvfGPipelineBuilderSetInputTopology(KvfGraphicsPipelineBuilder* builder, VkPrimitiveTopology topology)
@@ -2167,6 +2226,20 @@ void kvfGPipelineBuilderSetCullMode(KvfGraphicsPipelineBuilder* builder, VkCullM
builder->rasterization_state.frontFace = face; builder->rasterization_state.frontFace = face;
} }
void kvfGPipelineBuilderSetMultisampling(KvfGraphicsPipelineBuilder* builder, VkSampleCountFlagBits count)
{
KVF_ASSERT(builder != NULL);
builder->multisampling.rasterizationSamples = count;
}
void kvfGPipelineBuilderSetMultisamplingShading(KvfGraphicsPipelineBuilder* builder, VkSampleCountFlagBits count, float min_sampling_shading)
{
KVF_ASSERT(builder != NULL);
builder->multisampling.rasterizationSamples = count;
builder->multisampling.sampleShadingEnable = VK_TRUE;
builder->multisampling.minSampleShading = min_sampling_shading;
}
void kvfGPipelineBuilderDisableBlending(KvfGraphicsPipelineBuilder* builder) void kvfGPipelineBuilderDisableBlending(KvfGraphicsPipelineBuilder* builder)
{ {
KVF_ASSERT(builder != NULL); KVF_ASSERT(builder != NULL);
@@ -2298,11 +2371,6 @@ VkPipeline kvfCreateGraphicsPipeline(VkDevice device, VkPipelineLayout layout, K
viewport_state.scissorCount = 1; viewport_state.scissorCount = 1;
viewport_state.pScissors = NULL; viewport_state.pScissors = NULL;
VkPipelineMultisampleStateCreateInfo multisampling = {};
multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampling.sampleShadingEnable = VK_FALSE;
multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
VkGraphicsPipelineCreateInfo pipeline_info = {}; VkGraphicsPipelineCreateInfo pipeline_info = {};
pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipeline_info.stageCount = builder->shader_stages_count; pipeline_info.stageCount = builder->shader_stages_count;
@@ -2311,7 +2379,7 @@ VkPipeline kvfCreateGraphicsPipeline(VkDevice device, VkPipelineLayout layout, K
pipeline_info.pInputAssemblyState = &builder->input_assembly_state; pipeline_info.pInputAssemblyState = &builder->input_assembly_state;
pipeline_info.pViewportState = &viewport_state; pipeline_info.pViewportState = &viewport_state;
pipeline_info.pRasterizationState = &builder->rasterization_state; pipeline_info.pRasterizationState = &builder->rasterization_state;
pipeline_info.pMultisampleState = &multisampling; pipeline_info.pMultisampleState = &builder->multisampling;
pipeline_info.pColorBlendState = &color_blending; pipeline_info.pColorBlendState = &color_blending;
pipeline_info.pDynamicState = &dynamic_states; pipeline_info.pDynamicState = &dynamic_states;
pipeline_info.layout = layout; pipeline_info.layout = layout;