mirror of
https://github.com/love2d/love.git
synced 2026-08-20 20:49:54 +02:00
vulkan: adjust code styling
This commit is contained in:
@@ -70,10 +70,6 @@ struct Rect
|
|||||||
{
|
{
|
||||||
return x == rhs.x && y == rhs.y && w == rhs.w && h == rhs.h;
|
return x == rhs.x && y == rhs.y && w == rhs.w && h == rhs.h;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator != (const Rect& rhs) const {
|
|
||||||
return !(*this == rhs);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inline int nextP2(int x)
|
inline int nextP2(int x)
|
||||||
|
|||||||
@@ -673,8 +673,7 @@ int luax_catchexcept(lua_State *L, const T& func)
|
|||||||
catch (const std::exception &e)
|
catch (const std::exception &e)
|
||||||
{
|
{
|
||||||
should_error = true;
|
should_error = true;
|
||||||
const char* msg = e.what();
|
lua_pushstring(L, e.what());
|
||||||
lua_pushstring(L, msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (should_error)
|
if (should_error)
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ static const char global_syntax[] = R"(
|
|||||||
#define mediump
|
#define mediump
|
||||||
#define highp
|
#define highp
|
||||||
#endif
|
#endif
|
||||||
#if defined(VERTEX) || __VERSION__ > 100 || defined(GL_FRAGMENT_PRECISION_HIGH) || defined(USE_VULKAN)
|
#if defined(VERTEX) || __VERSION__ > 100 || defined(GL_FRAGMENT_PRECISION_HIGH)
|
||||||
#define LOVE_HIGHP_OR_MEDIUMP highp
|
#define LOVE_HIGHP_OR_MEDIUMP highp
|
||||||
#else
|
#else
|
||||||
#define LOVE_HIGHP_OR_MEDIUMP mediump
|
#define LOVE_HIGHP_OR_MEDIUMP mediump
|
||||||
@@ -248,8 +248,8 @@ LOVE_IO_LOCATION(0) attribute vec4 VertexPosition;
|
|||||||
LOVE_IO_LOCATION(1) attribute vec4 VertexTexCoord;
|
LOVE_IO_LOCATION(1) attribute vec4 VertexTexCoord;
|
||||||
LOVE_IO_LOCATION(2) attribute vec4 VertexColor;
|
LOVE_IO_LOCATION(2) attribute vec4 VertexColor;
|
||||||
|
|
||||||
LOVE_IO_LOCATION(0) varying vec4 VaryingTexCoord;
|
varying vec4 VaryingTexCoord;
|
||||||
LOVE_IO_LOCATION(1) varying vec4 VaryingColor;
|
varying vec4 VaryingColor;
|
||||||
|
|
||||||
vec4 position(mat4 clipSpaceFromLocal, vec4 localPosition);
|
vec4 position(mat4 clipSpaceFromLocal, vec4 localPosition);
|
||||||
|
|
||||||
@@ -316,8 +316,8 @@ static const char pixel_main[] = R"(
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
uniform sampler2D MainTex;
|
uniform sampler2D MainTex;
|
||||||
LOVE_IO_LOCATION(0) varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord;
|
varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord;
|
||||||
LOVE_IO_LOCATION(1) varying mediump vec4 VaryingColor;
|
varying mediump vec4 VaryingColor;
|
||||||
|
|
||||||
vec4 effect(vec4 vcolor, Image tex, vec2 texcoord, vec2 pixcoord);
|
vec4 effect(vec4 vcolor, Image tex, vec2 texcoord, vec2 pixcoord);
|
||||||
|
|
||||||
@@ -351,8 +351,8 @@ static const char pixel_main_custom[] = R"(
|
|||||||
#define LOVE_MULTI_CANVASES 1
|
#define LOVE_MULTI_CANVASES 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
LOVE_IO_LOCATION(0) varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord;
|
varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord;
|
||||||
LOVE_IO_LOCATION(1) varying mediump vec4 VaryingColor;
|
varying mediump vec4 VaryingColor;
|
||||||
|
|
||||||
void effect();
|
void effect();
|
||||||
|
|
||||||
@@ -574,8 +574,7 @@ std::string Shader::createShaderStageCode(Graphics *gfx, ShaderStageType stage,
|
|||||||
ss << ((!gles && (lang == Shader::LANGUAGE_GLSL1 || glsl1on3)) ? "#line 0\n" : "#line 1\n");
|
ss << ((!gles && (lang == Shader::LANGUAGE_GLSL1 || glsl1on3)) ? "#line 0\n" : "#line 1\n");
|
||||||
ss << code;
|
ss << code;
|
||||||
|
|
||||||
auto result = ss.str();
|
return ss.str();
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Shader::Shader(StrongRef<ShaderStage> _stages[])
|
Shader::Shader(StrongRef<ShaderStage> _stages[])
|
||||||
@@ -877,8 +876,7 @@ bool Shader::validateInternal(StrongRef<ShaderStage> stages[], std::string &err,
|
|||||||
{
|
{
|
||||||
LocalUniform u = {};
|
LocalUniform u = {};
|
||||||
auto &values = u.initializerValues;
|
auto &values = u.initializerValues;
|
||||||
// const glslang::TConstUnionArray *constarray = info.getConstArray(); was this function deprecated in a later version?
|
const glslang::TConstUnionArray *constarray = info.getConstArray();
|
||||||
const glslang::TConstUnionArray* constarray = nullptr;
|
|
||||||
|
|
||||||
// Store initializer values for local uniforms. Some love graphics
|
// Store initializer values for local uniforms. Some love graphics
|
||||||
// backends strip these out of the shader so we need to be able to
|
// backends strip these out of the shader so we need to be able to
|
||||||
|
|||||||
@@ -18,8 +18,6 @@
|
|||||||
* 3. This notice may not be removed or altered from any source distribution.
|
* 3. This notice may not be removed or altered from any source distribution.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include "ShaderStage.h"
|
#include "ShaderStage.h"
|
||||||
#include "common/Exception.h"
|
#include "common/Exception.h"
|
||||||
#include "Graphics.h"
|
#include "Graphics.h"
|
||||||
@@ -178,8 +176,7 @@ ShaderStage::ShaderStage(Graphics *gfx, ShaderStageType stage, const std::string
|
|||||||
|
|
||||||
std::string err = "Error validating " + std::string(stagename) + " shader:\n\n"
|
std::string err = "Error validating " + std::string(stagename) + " shader:\n\n"
|
||||||
+ std::string(glslangShader->getInfoLog()) + "\n"
|
+ std::string(glslangShader->getInfoLog()) + "\n"
|
||||||
+ std::string(glslangShader->getInfoDebugLog()) + "\n\nShader Code:\n"
|
+ std::string(glslangShader->getInfoDebugLog());
|
||||||
+ glsl;
|
|
||||||
|
|
||||||
delete glslangShader;
|
delete glslangShader;
|
||||||
throw love::Exception("%s", err.c_str());
|
throw love::Exception("%s", err.c_str());
|
||||||
|
|||||||
@@ -46,8 +46,8 @@ public:
|
|||||||
bool loadVolatile() override;
|
bool loadVolatile() override;
|
||||||
void unloadVolatile() override;
|
void unloadVolatile() override;
|
||||||
|
|
||||||
void copyFromBuffer(love::graphics::Buffer* source, size_t sourceoffset, int sourcewidth, size_t size, int slice, int mipmap, const Rect& rect) override;
|
void copyFromBuffer(love::graphics::Buffer *source, size_t sourceoffset, int sourcewidth, size_t size, int slice, int mipmap, const Rect &rect) override;
|
||||||
void copyToBuffer(love::graphics::Buffer* dest, int slice, int mipmap, const Rect& rect, size_t destoffset, int destwidth, size_t size) override;
|
void copyToBuffer(love::graphics::Buffer *dest, int slice, int mipmap, const Rect &rect, size_t destoffset, int destwidth, size_t size) override;
|
||||||
|
|
||||||
void setSamplerState(const SamplerState &s) override;
|
void setSamplerState(const SamplerState &s) override;
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
#include "Buffer.h"
|
#include "Buffer.h"
|
||||||
#include "Graphics.h"
|
#include "Graphics.h"
|
||||||
|
|
||||||
namespace love {
|
namespace love
|
||||||
namespace graphics {
|
{
|
||||||
namespace vulkan {
|
namespace graphics
|
||||||
|
{
|
||||||
|
namespace vulkan
|
||||||
|
{
|
||||||
|
|
||||||
static VkBufferUsageFlags getUsageBit(BufferUsage mode) {
|
static VkBufferUsageFlags getUsageBit(BufferUsage mode)
|
||||||
switch (mode) {
|
{
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
case BUFFERUSAGE_VERTEX: return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
|
case BUFFERUSAGE_VERTEX: return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
|
||||||
case BUFFERUSAGE_INDEX: return VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
|
case BUFFERUSAGE_INDEX: return VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
|
||||||
case BUFFERUSAGE_UNIFORM: return VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
|
case BUFFERUSAGE_UNIFORM: return VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
|
||||||
@@ -15,35 +20,37 @@ static VkBufferUsageFlags getUsageBit(BufferUsage mode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static VkBufferUsageFlags getVulkanUsageFlags(BufferUsageFlags flags) {
|
static VkBufferUsageFlags getVulkanUsageFlags(BufferUsageFlags flags)
|
||||||
|
{
|
||||||
VkBufferUsageFlags vkFlags = 0;
|
VkBufferUsageFlags vkFlags = 0;
|
||||||
for (int i = 0; i < BUFFERUSAGE_MAX_ENUM; i++) {
|
for (int i = 0; i < BUFFERUSAGE_MAX_ENUM; i++)
|
||||||
|
{
|
||||||
BufferUsageFlags flag = static_cast<BufferUsageFlags>(1u << i);
|
BufferUsageFlags flag = static_cast<BufferUsageFlags>(1u << i);
|
||||||
if (flags & flag) {
|
if (flags & flag)
|
||||||
vkFlags |= getUsageBit((BufferUsage)i);
|
vkFlags |= getUsageBit((BufferUsage)i);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return vkFlags;
|
return vkFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer::Buffer(love::graphics::Graphics* gfx, const Settings& settings, const std::vector<DataDeclaration>& format, const void* data, size_t size, size_t arraylength)
|
Buffer::Buffer(love::graphics::Graphics *gfx, const Settings &settings, const std::vector<DataDeclaration> &format, const void *data, size_t size, size_t arraylength)
|
||||||
: love::graphics::Buffer(gfx, settings, format, size, arraylength), usageFlags(settings.usageFlags), gfx(gfx) {
|
: love::graphics::Buffer(gfx, settings, format, size, arraylength)
|
||||||
|
, usageFlags(settings.usageFlags)
|
||||||
|
, vgfx(dynamic_cast<Graphics*>(gfx))
|
||||||
|
{
|
||||||
loadVolatile();
|
loadVolatile();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Buffer::loadVolatile() {
|
bool Buffer::loadVolatile()
|
||||||
Graphics* vgfx = (Graphics*)gfx;
|
{
|
||||||
allocator = vgfx->getVmaAllocator();
|
allocator = vgfx->getVmaAllocator();
|
||||||
|
|
||||||
VkBufferCreateInfo bufferInfo{};
|
VkBufferCreateInfo bufferInfo{};
|
||||||
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||||
bufferInfo.size = getSize();
|
bufferInfo.size = getSize();
|
||||||
if (dataUsage == BUFFERDATAUSAGE_READBACK) {
|
if (dataUsage == BUFFERDATAUSAGE_READBACK)
|
||||||
bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
||||||
}
|
else
|
||||||
else {
|
|
||||||
bufferInfo.usage = getVulkanUsageFlags(usageFlags);
|
bufferInfo.usage = getVulkanUsageFlags(usageFlags);
|
||||||
}
|
|
||||||
|
|
||||||
VmaAllocationCreateInfo allocCreateInfo = {};
|
VmaAllocationCreateInfo allocCreateInfo = {};
|
||||||
allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO;
|
allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO;
|
||||||
@@ -54,11 +61,11 @@ bool Buffer::loadVolatile() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Buffer::unloadVolatile() {
|
void Buffer::unloadVolatile()
|
||||||
|
{
|
||||||
if (buffer == VK_NULL_HANDLE)
|
if (buffer == VK_NULL_HANDLE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Graphics* vgfx = (Graphics*)gfx;
|
|
||||||
auto device = vgfx->getDevice();
|
auto device = vgfx->getDevice();
|
||||||
|
|
||||||
vgfx->queueCleanUp(
|
vgfx->queueCleanUp(
|
||||||
@@ -70,29 +77,43 @@ void Buffer::unloadVolatile() {
|
|||||||
buffer = VK_NULL_HANDLE;
|
buffer = VK_NULL_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer::~Buffer() {
|
Buffer::~Buffer()
|
||||||
|
{
|
||||||
unloadVolatile();
|
unloadVolatile();
|
||||||
}
|
}
|
||||||
|
|
||||||
void* Buffer::map(MapType map, size_t offset, size_t size) {
|
ptrdiff_t Buffer::getHandle() const
|
||||||
|
{
|
||||||
|
return (ptrdiff_t) buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptrdiff_t Buffer::getTexelBufferHandle() const
|
||||||
|
{
|
||||||
|
throw love::Exception("unimplemented Buffer::getTexelBufferHandle");
|
||||||
|
return (ptrdiff_t) nullptr; // todo ?
|
||||||
|
}
|
||||||
|
|
||||||
|
void* Buffer::map(MapType map, size_t offset, size_t size)
|
||||||
|
{
|
||||||
char* data = (char*)allocInfo.pMappedData;
|
char* data = (char*)allocInfo.pMappedData;
|
||||||
return (void*) (data + offset);
|
return (void*) (data + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Buffer::fill(size_t offset, size_t size, const void *data) {
|
bool Buffer::fill(size_t offset, size_t size, const void *data)
|
||||||
|
{
|
||||||
void* dst = (void*)((char*)allocInfo.pMappedData + offset);
|
void* dst = (void*)((char*)allocInfo.pMappedData + offset);
|
||||||
memcpy(dst, data, size);
|
memcpy(dst, data, size);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Buffer::unmap(size_t usedoffset, size_t usedsize) {
|
void Buffer::unmap(size_t usedoffset, size_t usedsize)
|
||||||
|
{
|
||||||
(void)usedoffset;
|
(void)usedoffset;
|
||||||
(void)usedsize;
|
(void)usedsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Buffer::copyTo(love::graphics::Buffer* dest, size_t sourceoffset, size_t destoffset, size_t size) {
|
void Buffer::copyTo(love::graphics::Buffer *dest, size_t sourceoffset, size_t destoffset, size_t size)
|
||||||
Graphics* vgfx = (Graphics*)gfx;
|
{
|
||||||
|
|
||||||
auto commandBuffer = vgfx->getReadbackCommandBuffer();
|
auto commandBuffer = vgfx->getReadbackCommandBuffer();
|
||||||
|
|
||||||
VkBufferCopy bufferCopy{};
|
VkBufferCopy bufferCopy{};
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef LOVE_GRAPHICS_VULKAN_BUFFER_H
|
#pragma once
|
||||||
#define LOVE_GRAPHICS_VULKAN_BUFFER_H
|
|
||||||
|
|
||||||
#include "graphics/Buffer.h"
|
#include "graphics/Buffer.h"
|
||||||
#include "graphics/Volatile.h"
|
#include "graphics/Volatile.h"
|
||||||
@@ -7,40 +6,43 @@
|
|||||||
#include "VulkanWrapper.h"
|
#include "VulkanWrapper.h"
|
||||||
|
|
||||||
|
|
||||||
namespace love {
|
namespace love
|
||||||
namespace graphics {
|
{
|
||||||
namespace vulkan {
|
namespace graphics
|
||||||
class Buffer : public love::graphics::Buffer, public Volatile {
|
{
|
||||||
|
namespace vulkan
|
||||||
|
{
|
||||||
|
|
||||||
|
class Graphics;
|
||||||
|
|
||||||
|
class Buffer
|
||||||
|
: public love::graphics::Buffer
|
||||||
|
, public Volatile
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
Buffer(love::graphics::Graphics* gfx, const Settings& settings, const std::vector<DataDeclaration>& format, const void* data, size_t size, size_t arraylength);
|
Buffer(love::graphics::Graphics *gfx, const Settings& settings, const std::vector<DataDeclaration> &format, const void *data, size_t size, size_t arraylength);
|
||||||
virtual ~Buffer();
|
virtual ~Buffer();
|
||||||
|
|
||||||
virtual bool loadVolatile() override;
|
virtual bool loadVolatile() override;
|
||||||
virtual void unloadVolatile() override;
|
virtual void unloadVolatile() override;
|
||||||
|
|
||||||
void* map(MapType map, size_t offset, size_t size) override;
|
void *map(MapType map, size_t offset, size_t size) override;
|
||||||
void unmap(size_t usedoffset, size_t usedsize) override;
|
void unmap(size_t usedoffset, size_t usedsize) override;
|
||||||
bool fill(size_t offset, size_t size, const void* data) override;
|
bool fill(size_t offset, size_t size, const void *data) override;
|
||||||
void copyTo(love::graphics::Buffer* dest, size_t sourceoffset, size_t destoffset, size_t size) override;
|
void copyTo(love::graphics::Buffer *dest, size_t sourceoffset, size_t destoffset, size_t size) override;
|
||||||
ptrdiff_t getHandle() const override {
|
ptrdiff_t getHandle() const override;
|
||||||
return (ptrdiff_t) buffer; // todo ?
|
ptrdiff_t getTexelBufferHandle() const override;
|
||||||
}
|
|
||||||
ptrdiff_t getTexelBufferHandle() const override {
|
|
||||||
throw love::Exception("unimplemented Buffer::getTexelBufferHandle");
|
|
||||||
return (ptrdiff_t) nullptr; // todo ?
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// todo use a staging buffer for improved performance
|
// todo use a staging buffer for improved performance
|
||||||
VkBuffer buffer = VK_NULL_HANDLE;
|
VkBuffer buffer = VK_NULL_HANDLE;
|
||||||
love::graphics::Graphics* gfx;
|
Graphics *vgfx = nullptr;
|
||||||
VmaAllocator allocator;
|
VmaAllocator allocator;
|
||||||
VmaAllocation allocation;
|
VmaAllocation allocation;
|
||||||
VmaAllocationInfo allocInfo;
|
VmaAllocationInfo allocInfo;
|
||||||
BufferUsageFlags usageFlags;
|
BufferUsageFlags usageFlags;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // vulkan
|
} // vulkan
|
||||||
} // graphics
|
} // graphics
|
||||||
} // love
|
} // love
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,4 @@
|
|||||||
#ifndef LOVE_GRAPHICS_VULKAN_GRAPHICS_H
|
#pragma once
|
||||||
#define LOVE_GRAPHICS_VULKAN_GRAPHICS_H
|
|
||||||
|
|
||||||
// löve
|
// löve
|
||||||
#include "common/config.h"
|
#include "common/config.h"
|
||||||
@@ -20,27 +19,36 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
|
|
||||||
namespace love {
|
namespace love
|
||||||
namespace graphics {
|
{
|
||||||
namespace vulkan {
|
namespace graphics
|
||||||
struct RenderPassConfiguration {
|
{
|
||||||
|
namespace vulkan
|
||||||
|
{
|
||||||
|
|
||||||
|
struct RenderPassConfiguration
|
||||||
|
{
|
||||||
std::vector<VkFormat> colorFormats;
|
std::vector<VkFormat> colorFormats;
|
||||||
|
|
||||||
struct StaticRenderPassConfiguration {
|
struct StaticRenderPassConfiguration
|
||||||
|
{
|
||||||
VkImageLayout initialColorImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
VkImageLayout initialColorImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT;
|
VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
VkFormat depthFormat = VK_FORMAT_UNDEFINED;
|
VkFormat depthFormat = VK_FORMAT_UNDEFINED;
|
||||||
bool resolve = false;
|
bool resolve = false;
|
||||||
} staticData;
|
} staticData;
|
||||||
|
|
||||||
bool operator==(const RenderPassConfiguration& conf) const {
|
bool operator==(const RenderPassConfiguration &conf) const
|
||||||
|
{
|
||||||
return colorFormats == conf.colorFormats &&
|
return colorFormats == conf.colorFormats &&
|
||||||
(memcmp(&staticData, &conf.staticData, sizeof(StaticRenderPassConfiguration)) == 0);
|
(memcmp(&staticData, &conf.staticData, sizeof(StaticRenderPassConfiguration)) == 0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RenderPassConfigurationHasher {
|
struct RenderPassConfigurationHasher
|
||||||
size_t operator()(const RenderPassConfiguration &configuration) const {
|
{
|
||||||
|
size_t operator()(const RenderPassConfiguration &configuration) const
|
||||||
|
{
|
||||||
size_t hashes[] = {
|
size_t hashes[] = {
|
||||||
XXH32(configuration.colorFormats.data(), configuration.colorFormats.size() * sizeof(VkFormat), 0),
|
XXH32(configuration.colorFormats.data(), configuration.colorFormats.size() * sizeof(VkFormat), 0),
|
||||||
XXH32(&configuration.staticData, sizeof(configuration.staticData), 0),
|
XXH32(&configuration.staticData, sizeof(configuration.staticData), 0),
|
||||||
@@ -49,10 +57,12 @@ struct RenderPassConfigurationHasher {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FramebufferConfiguration {
|
struct FramebufferConfiguration
|
||||||
|
{
|
||||||
std::vector<VkImageView> colorViews;
|
std::vector<VkImageView> colorViews;
|
||||||
|
|
||||||
struct StaticFramebufferConfiguration {
|
struct StaticFramebufferConfiguration
|
||||||
|
{
|
||||||
VkImageView depthView = VK_NULL_HANDLE;
|
VkImageView depthView = VK_NULL_HANDLE;
|
||||||
VkImageView resolveView = VK_NULL_HANDLE;
|
VkImageView resolveView = VK_NULL_HANDLE;
|
||||||
|
|
||||||
@@ -62,14 +72,17 @@ struct FramebufferConfiguration {
|
|||||||
VkRenderPass renderPass = VK_NULL_HANDLE;
|
VkRenderPass renderPass = VK_NULL_HANDLE;
|
||||||
} staticData;
|
} staticData;
|
||||||
|
|
||||||
bool operator==(const FramebufferConfiguration& conf) const {
|
bool operator==(const FramebufferConfiguration &conf) const
|
||||||
|
{
|
||||||
return colorViews == conf.colorViews &&
|
return colorViews == conf.colorViews &&
|
||||||
(memcmp(&staticData, &conf.staticData, sizeof(StaticFramebufferConfiguration)) == 0);
|
(memcmp(&staticData, &conf.staticData, sizeof(StaticFramebufferConfiguration)) == 0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FramebufferConfigurationHasher {
|
struct FramebufferConfigurationHasher
|
||||||
size_t operator()(const FramebufferConfiguration& configuration) const {
|
{
|
||||||
|
size_t operator()(const FramebufferConfiguration &configuration) const
|
||||||
|
{
|
||||||
size_t hashes[] = {
|
size_t hashes[] = {
|
||||||
XXH32(configuration.colorViews.data(), configuration.colorViews.size() * sizeof(VkImageView), 0),
|
XXH32(configuration.colorViews.data(), configuration.colorViews.size() * sizeof(VkImageView), 0),
|
||||||
XXH32(&configuration.staticData, sizeof(configuration.staticData), 0),
|
XXH32(&configuration.staticData, sizeof(configuration.staticData), 0),
|
||||||
@@ -79,16 +92,19 @@ struct FramebufferConfigurationHasher {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OptionalInstanceExtensions {
|
struct OptionalInstanceExtensions
|
||||||
|
{
|
||||||
bool physicalDeviceProperties2 = false;
|
bool physicalDeviceProperties2 = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OptionalDeviceFeatures {
|
struct OptionalDeviceFeatures
|
||||||
|
{
|
||||||
bool extendedDynamicState = false;
|
bool extendedDynamicState = false;
|
||||||
bool pushDescriptor = false;
|
bool pushDescriptor = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OptionalDeviceExtensionFunctions {
|
struct OptionalDeviceExtensionFunctions
|
||||||
|
{
|
||||||
// extended dynamic state
|
// extended dynamic state
|
||||||
PFN_vkCmdSetCullModeEXT vkCmdSetCullModeEXT = nullptr;
|
PFN_vkCmdSetCullModeEXT vkCmdSetCullModeEXT = nullptr;
|
||||||
PFN_vkCmdSetDepthBoundsTestEnableEXT vkCmdSetDepthBoundsTestEnableEXT = nullptr;
|
PFN_vkCmdSetDepthBoundsTestEnableEXT vkCmdSetDepthBoundsTestEnableEXT = nullptr;
|
||||||
@@ -106,7 +122,8 @@ struct OptionalDeviceExtensionFunctions {
|
|||||||
PFN_vkCmdPushDescriptorSetKHR vkCmdPushDescriptorSetKHR = nullptr;
|
PFN_vkCmdPushDescriptorSetKHR vkCmdPushDescriptorSetKHR = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GraphicsPipelineConfiguration {
|
struct GraphicsPipelineConfiguration
|
||||||
|
{
|
||||||
VkRenderPass renderPass;
|
VkRenderPass renderPass;
|
||||||
VertexAttributes vertexAttributes;
|
VertexAttributes vertexAttributes;
|
||||||
Shader* shader = nullptr;
|
Shader* shader = nullptr;
|
||||||
@@ -117,7 +134,8 @@ struct GraphicsPipelineConfiguration {
|
|||||||
uint32_t numColorAttachments;
|
uint32_t numColorAttachments;
|
||||||
PrimitiveType primitiveType;
|
PrimitiveType primitiveType;
|
||||||
|
|
||||||
struct DynamicState {
|
struct DynamicState
|
||||||
|
{
|
||||||
CullMode cullmode = CULL_NONE;
|
CullMode cullmode = CULL_NONE;
|
||||||
Winding winding = WINDING_MAX_ENUM;
|
Winding winding = WINDING_MAX_ENUM;
|
||||||
StencilAction stencilAction = STENCIL_MAX_ENUM;
|
StencilAction stencilAction = STENCIL_MAX_ENUM;
|
||||||
@@ -125,34 +143,42 @@ struct GraphicsPipelineConfiguration {
|
|||||||
DepthState depthState{};
|
DepthState depthState{};
|
||||||
} dynamicState;
|
} dynamicState;
|
||||||
|
|
||||||
GraphicsPipelineConfiguration() {
|
GraphicsPipelineConfiguration()
|
||||||
|
{
|
||||||
memset(this, 0, sizeof(GraphicsPipelineConfiguration));
|
memset(this, 0, sizeof(GraphicsPipelineConfiguration));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const GraphicsPipelineConfiguration& other) const {
|
bool operator==(const GraphicsPipelineConfiguration &other) const
|
||||||
|
{
|
||||||
return memcmp(this, &other, sizeof(GraphicsPipelineConfiguration)) == 0;
|
return memcmp(this, &other, sizeof(GraphicsPipelineConfiguration)) == 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GraphicsPipelineConfigurationHasher {
|
struct GraphicsPipelineConfigurationHasher
|
||||||
size_t operator() (const GraphicsPipelineConfiguration &configuration) const {
|
{
|
||||||
|
size_t operator() (const GraphicsPipelineConfiguration &configuration) const
|
||||||
|
{
|
||||||
return XXH32(&configuration, sizeof(GraphicsPipelineConfiguration), 0);
|
return XXH32(&configuration, sizeof(GraphicsPipelineConfiguration), 0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SamplerStateHasher {
|
struct SamplerStateHasher
|
||||||
size_t operator()(const SamplerState &samplerState) const {
|
{
|
||||||
|
size_t operator()(const SamplerState &samplerState) const
|
||||||
|
{
|
||||||
return XXH32(&samplerState, sizeof(SamplerState), 0);
|
return XXH32(&samplerState, sizeof(SamplerState), 0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BatchedDrawBuffers {
|
struct BatchedDrawBuffers
|
||||||
|
{
|
||||||
StreamBuffer* vertexBuffer1;
|
StreamBuffer* vertexBuffer1;
|
||||||
StreamBuffer* vertexBuffer2;
|
StreamBuffer* vertexBuffer2;
|
||||||
StreamBuffer* indexBuffer;
|
StreamBuffer* indexBuffer;
|
||||||
StreamBuffer* constantColorBuffer;
|
StreamBuffer* constantColorBuffer;
|
||||||
|
|
||||||
~BatchedDrawBuffers() {
|
~BatchedDrawBuffers()
|
||||||
|
{
|
||||||
delete vertexBuffer1;
|
delete vertexBuffer1;
|
||||||
delete vertexBuffer2;
|
delete vertexBuffer2;
|
||||||
delete indexBuffer;
|
delete indexBuffer;
|
||||||
@@ -160,22 +186,26 @@ struct BatchedDrawBuffers {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct QueueFamilyIndices {
|
struct QueueFamilyIndices
|
||||||
|
{
|
||||||
std::optional<uint32_t> graphicsFamily;
|
std::optional<uint32_t> graphicsFamily;
|
||||||
std::optional<uint32_t> presentFamily;
|
std::optional<uint32_t> presentFamily;
|
||||||
|
|
||||||
bool isComplete() const {
|
bool isComplete() const
|
||||||
|
{
|
||||||
return graphicsFamily.has_value() && presentFamily.has_value();
|
return graphicsFamily.has_value() && presentFamily.has_value();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SwapChainSupportDetails {
|
struct SwapChainSupportDetails
|
||||||
|
{
|
||||||
VkSurfaceCapabilitiesKHR capabilities{};
|
VkSurfaceCapabilitiesKHR capabilities{};
|
||||||
std::vector<VkSurfaceFormatKHR> formats;
|
std::vector<VkSurfaceFormatKHR> formats;
|
||||||
std::vector<VkPresentModeKHR> presentModes;
|
std::vector<VkPresentModeKHR> presentModes;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Graphics final : public love::graphics::Graphics {
|
class Graphics final : public love::graphics::Graphics
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
#ifdef LOVE_ANDROID
|
#ifdef LOVE_ANDROID
|
||||||
Graphics() {
|
Graphics() {
|
||||||
@@ -196,27 +226,27 @@ public:
|
|||||||
const VmaAllocator getVmaAllocator() const;
|
const VmaAllocator getVmaAllocator() const;
|
||||||
|
|
||||||
// implementation for virtual functions
|
// implementation for virtual functions
|
||||||
love::graphics::Texture* newTexture(const love::graphics::Texture::Settings& settings, const love::graphics::Texture::Slices* data) override;
|
love::graphics::Texture *newTexture(const love::graphics::Texture::Settings &settings, const love::graphics::Texture::Slices *data) override;
|
||||||
love::graphics::Buffer* newBuffer(const love::graphics::Buffer::Settings& settings, const std::vector<love::graphics::Buffer::DataDeclaration>& format, const void* data, size_t size, size_t arraylength) override;
|
love::graphics::Buffer *newBuffer(const love::graphics::Buffer::Settings &settings, const std::vector<love::graphics::Buffer::DataDeclaration>& format, const void *data, size_t size, size_t arraylength) override;
|
||||||
void clear(OptionalColorD color, OptionalInt stencil, OptionalDouble depth) override;
|
void clear(OptionalColorD color, OptionalInt stencil, OptionalDouble depth) override;
|
||||||
void clear(const std::vector<OptionalColorD>& colors, OptionalInt stencil, OptionalDouble depth) override;
|
void clear(const std::vector<OptionalColorD> &colors, OptionalInt stencil, OptionalDouble depth) override;
|
||||||
Matrix4 computeDeviceProjection(const Matrix4& projection, bool rendertotexture) const override;
|
Matrix4 computeDeviceProjection(const Matrix4 &projection, bool rendertotexture) const override;
|
||||||
void discard(const std::vector<bool>& colorbuffers, bool depthstencil) override { }
|
void discard(const std::vector<bool> &colorbuffers, bool depthstencil) override { }
|
||||||
void present(void* screenshotCallbackdata) override;
|
void present(void *screenshotCallbackdata) override;
|
||||||
void setViewportSize(int width, int height, int pixelwidth, int pixelheight) override;
|
void setViewportSize(int width, int height, int pixelwidth, int pixelheight) override;
|
||||||
bool setMode(void* context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) override;
|
bool setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) override;
|
||||||
void unSetMode() override;
|
void unSetMode() override;
|
||||||
void setActive(bool active) override;
|
void setActive(bool active) override;
|
||||||
int getRequestedBackbufferMSAA() const override;
|
int getRequestedBackbufferMSAA() const override;
|
||||||
int getBackbufferMSAA() const override;
|
int getBackbufferMSAA() const override;
|
||||||
void setColor(Colorf c) override;
|
void setColor(Colorf c) override;
|
||||||
void setScissor(const Rect& rect) override;
|
void setScissor(const Rect &rect) override;
|
||||||
void setScissor() override;
|
void setScissor() override;
|
||||||
void setStencilMode(StencilAction action, CompareMode compare, int value, love::uint32 readmask, love::uint32 writemask) override;
|
void setStencilMode(StencilAction action, CompareMode compare, int value, love::uint32 readmask, love::uint32 writemask) override;
|
||||||
void setDepthMode(CompareMode compare, bool write) override;
|
void setDepthMode(CompareMode compare, bool write) override;
|
||||||
void setFrontFaceWinding(Winding winding) override;
|
void setFrontFaceWinding(Winding winding) override;
|
||||||
void setColorMask(ColorChannelMask mask) override;
|
void setColorMask(ColorChannelMask mask) override;
|
||||||
void setBlendState(const BlendState& blend) override;
|
void setBlendState(const BlendState &blend) override;
|
||||||
void setPointSize(float size) override;
|
void setPointSize(float size) override;
|
||||||
void setWireframe(bool enable) override;
|
void setWireframe(bool enable) override;
|
||||||
PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const override;
|
PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const override;
|
||||||
@@ -224,12 +254,12 @@ public:
|
|||||||
Renderer getRenderer() const override;
|
Renderer getRenderer() const override;
|
||||||
bool usesGLSLES() const override;
|
bool usesGLSLES() const override;
|
||||||
RendererInfo getRendererInfo() const override;
|
RendererInfo getRendererInfo() const override;
|
||||||
void draw(const DrawCommand& cmd) override;
|
void draw(const DrawCommand &cmd) override;
|
||||||
void draw(const DrawIndexedCommand& cmd) override;
|
void draw(const DrawIndexedCommand &cmd) override;
|
||||||
void drawQuads(int start, int count, const VertexAttributes& attributes, const BufferBindings& buffers, graphics::Texture* texture) override;
|
void drawQuads(int start, int count, const VertexAttributes &attributes, const BufferBindings &buffers, graphics::Texture *texture) override;
|
||||||
|
|
||||||
graphics::GraphicsReadback* newReadbackInternal(ReadbackMethod method, love::graphics::Buffer* buffer, size_t offset, size_t size, data::ByteData* dest, size_t destoffset) override;
|
graphics::GraphicsReadback *newReadbackInternal(ReadbackMethod method, love::graphics::Buffer *buffer, size_t offset, size_t size, data::ByteData *dest, size_t destoffset) override;
|
||||||
graphics::GraphicsReadback* newReadbackInternal(ReadbackMethod method, love::graphics::Texture* texture, int slice, int mipmap, const Rect& rect, image::ImageData* dest, int destx, int desty) override;
|
graphics::GraphicsReadback *newReadbackInternal(ReadbackMethod method, love::graphics::Texture *texture, int slice, int mipmap, const Rect &rect, image::ImageData *dest, int destx, int desty) override;
|
||||||
|
|
||||||
VkCommandBuffer getDataTransferCommandBuffer();
|
VkCommandBuffer getDataTransferCommandBuffer();
|
||||||
VkCommandBuffer getReadbackCommandBuffer();
|
VkCommandBuffer getReadbackCommandBuffer();
|
||||||
@@ -243,7 +273,7 @@ public:
|
|||||||
|
|
||||||
uint32_t getNumImagesInFlight() const;
|
uint32_t getNumImagesInFlight() const;
|
||||||
const VkDeviceSize getMinUniformBufferOffsetAlignment() const;
|
const VkDeviceSize getMinUniformBufferOffsetAlignment() const;
|
||||||
graphics::Texture* getDefaultTexture() const;
|
graphics::Texture *getDefaultTexture() const;
|
||||||
VkSampler getCachedSampler(const SamplerState&);
|
VkSampler getCachedSampler(const SamplerState&);
|
||||||
|
|
||||||
void setComputeShader(Shader*);
|
void setComputeShader(Shader*);
|
||||||
@@ -252,13 +282,13 @@ public:
|
|||||||
const OptionalDeviceExtensionFunctions &getExtensionFunctions() const;
|
const OptionalDeviceExtensionFunctions &getExtensionFunctions() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
graphics::ShaderStage* newShaderStageInternal(ShaderStageType stage, const std::string& cachekey, const std::string& source, bool gles) override;
|
graphics::ShaderStage *newShaderStageInternal(ShaderStageType stage, const std::string &cachekey, const std::string &source, bool gles) override;
|
||||||
graphics::Shader* newShaderInternal(StrongRef<love::graphics::ShaderStage> stages[SHADERSTAGE_MAX_ENUM]) override;
|
graphics::Shader *newShaderInternal(StrongRef<love::graphics::ShaderStage> stages[SHADERSTAGE_MAX_ENUM]) override;
|
||||||
graphics::StreamBuffer* newStreamBuffer(BufferUsage type, size_t size) override;
|
graphics::StreamBuffer *newStreamBuffer(BufferUsage type, size_t size) override;
|
||||||
bool dispatch(int x, int y, int z) override;
|
bool dispatch(int x, int y, int z) override;
|
||||||
void initCapabilities() override;
|
void initCapabilities() override;
|
||||||
void getAPIStats(int& shaderswitches) const override;
|
void getAPIStats(int &shaderswitches) const override;
|
||||||
void setRenderTargetsInternal(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture) override;
|
void setRenderTargetsInternal(const RenderTargets &rts, int pixelw, int pixelh, bool hasSRGBtexture) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void createVulkanInstance();
|
void createVulkanInstance();
|
||||||
@@ -272,21 +302,21 @@ private:
|
|||||||
void createSurface();
|
void createSurface();
|
||||||
bool checkDeviceExtensionSupport(VkPhysicalDevice device);
|
bool checkDeviceExtensionSupport(VkPhysicalDevice device);
|
||||||
SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device);
|
SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device);
|
||||||
VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats);
|
VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR> &availableFormats);
|
||||||
VkPresentModeKHR chooseSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes);
|
VkPresentModeKHR chooseSwapPresentMode(const std::vector<VkPresentModeKHR> &availablePresentModes);
|
||||||
VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities);
|
VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR &capabilities);
|
||||||
VkCompositeAlphaFlagBitsKHR chooseCompositeAlpha(const VkSurfaceCapabilitiesKHR& capabilities);
|
VkCompositeAlphaFlagBitsKHR chooseCompositeAlpha(const VkSurfaceCapabilitiesKHR &capabilities);
|
||||||
void createSwapChain();
|
void createSwapChain();
|
||||||
void createImageViews();
|
void createImageViews();
|
||||||
void createDefaultRenderPass();
|
void createDefaultRenderPass();
|
||||||
void createDefaultFramebuffers();
|
void createDefaultFramebuffers();
|
||||||
VkFramebuffer createFramebuffer(FramebufferConfiguration);
|
VkFramebuffer createFramebuffer(FramebufferConfiguration&);
|
||||||
VkFramebuffer getFramebuffer(FramebufferConfiguration);
|
VkFramebuffer getFramebuffer(FramebufferConfiguration&);
|
||||||
void createDefaultShaders();
|
void createDefaultShaders();
|
||||||
VkRenderPass createRenderPass(RenderPassConfiguration);
|
VkRenderPass createRenderPass(RenderPassConfiguration&);
|
||||||
VkPipeline createGraphicsPipeline(GraphicsPipelineConfiguration);
|
VkPipeline createGraphicsPipeline(GraphicsPipelineConfiguration&);
|
||||||
void createColorResources();
|
void createColorResources();
|
||||||
VkFormat findSupportedFormat(const std::vector<VkFormat>& candidates, VkImageTiling tiling, VkFormatFeatureFlags features);
|
VkFormat findSupportedFormat(const std::vector<VkFormat> &candidates, VkImageTiling tiling, VkFormatFeatureFlags features);
|
||||||
VkFormat findDepthFormat();
|
VkFormat findDepthFormat();
|
||||||
void createDepthResources();
|
void createDepthResources();
|
||||||
void createCommandPool();
|
void createCommandPool();
|
||||||
@@ -300,7 +330,7 @@ private:
|
|||||||
void beginFrame();
|
void beginFrame();
|
||||||
void startRecordingGraphicsCommands(bool newFrame);
|
void startRecordingGraphicsCommands(bool newFrame);
|
||||||
void endRecordingGraphicsCommands(bool present);
|
void endRecordingGraphicsCommands(bool present);
|
||||||
void ensureGraphicsPipelineConfiguration(GraphicsPipelineConfiguration);
|
void ensureGraphicsPipelineConfiguration(GraphicsPipelineConfiguration&);
|
||||||
graphics::Shader::BuiltinUniformData getCurrentBuiltinUniformData();
|
graphics::Shader::BuiltinUniformData getCurrentBuiltinUniformData();
|
||||||
void updatedBatchedDrawBuffers();
|
void updatedBatchedDrawBuffers();
|
||||||
bool usesConstantVertexColor(const VertexAttributes&);
|
bool usesConstantVertexColor(const VertexAttributes&);
|
||||||
@@ -308,8 +338,8 @@ private:
|
|||||||
VertexAttributes vertexAttributes,
|
VertexAttributes vertexAttributes,
|
||||||
std::vector<VkVertexInputBindingDescription> &bindingDescriptions,
|
std::vector<VkVertexInputBindingDescription> &bindingDescriptions,
|
||||||
std::vector<VkVertexInputAttributeDescription> &attributeDescriptions);
|
std::vector<VkVertexInputAttributeDescription> &attributeDescriptions);
|
||||||
void prepareDraw(const VertexAttributes& attributes, const BufferBindings& buffers, graphics::Texture* texture, PrimitiveType, CullMode);
|
void prepareDraw(const VertexAttributes &attributes, const BufferBindings &buffers, graphics::Texture *texture, PrimitiveType, CullMode);
|
||||||
void startRenderPass(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture);
|
void startRenderPass(const RenderTargets &rts, int pixelw, int pixelh, bool hasSRGBtexture);
|
||||||
void startDefaultRenderPass();
|
void startDefaultRenderPass();
|
||||||
void endRenderPass();
|
void endRenderPass();
|
||||||
VkSampler createSampler(const SamplerState&);
|
VkSampler createSampler(const SamplerState&);
|
||||||
@@ -378,8 +408,7 @@ private:
|
|||||||
float currentViewportHeight = 0;
|
float currentViewportHeight = 0;
|
||||||
VkSampleCountFlagBits currentMsaaSamples = VK_SAMPLE_COUNT_1_BIT;
|
VkSampleCountFlagBits currentMsaaSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // vulkan
|
} // vulkan
|
||||||
} // graphics
|
} // graphics
|
||||||
} // love
|
} // love
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -4,21 +4,26 @@
|
|||||||
#include "Graphics.h"
|
#include "Graphics.h"
|
||||||
#include "data/ByteData.h"
|
#include "data/ByteData.h"
|
||||||
|
|
||||||
namespace love {
|
namespace love
|
||||||
namespace graphics {
|
{
|
||||||
namespace vulkan {
|
namespace graphics
|
||||||
|
{
|
||||||
GraphicsReadback::GraphicsReadback(love::graphics::Graphics* gfx, ReadbackMethod method, love::graphics::Buffer* buffer, size_t offset, size_t size, data::ByteData* dest, size_t destoffset)
|
namespace vulkan
|
||||||
: graphics::GraphicsReadback(gfx, method, buffer, offset, size, dest, destoffset) {
|
{
|
||||||
vgfx = dynamic_cast<Graphics*>(gfx);
|
|
||||||
|
|
||||||
|
GraphicsReadback::GraphicsReadback(love::graphics::Graphics *gfx, ReadbackMethod method, love::graphics::Buffer *buffer, size_t offset, size_t size, data::ByteData *dest, size_t destoffset)
|
||||||
|
: graphics::GraphicsReadback(gfx, method, buffer, offset, size, dest, destoffset)
|
||||||
|
, vgfx(dynamic_cast<Graphics*>(gfx))
|
||||||
|
{
|
||||||
// Immediate readback of readback-type buffers doesn't need a staging buffer.
|
// Immediate readback of readback-type buffers doesn't need a staging buffer.
|
||||||
if (method != READBACK_IMMEDIATE || buffer->getDataUsage() != BUFFERDATAUSAGE_READBACK) {
|
if (method != READBACK_IMMEDIATE || buffer->getDataUsage() != BUFFERDATAUSAGE_READBACK)
|
||||||
|
{
|
||||||
stagingBuffer = gfx->getTemporaryBuffer(size, DATAFORMAT_FLOAT, 0, BUFFERDATAUSAGE_READBACK);
|
stagingBuffer = gfx->getTemporaryBuffer(size, DATAFORMAT_FLOAT, 0, BUFFERDATAUSAGE_READBACK);
|
||||||
gfx->copyBuffer(buffer, stagingBuffer, offset, 0, size);
|
gfx->copyBuffer(buffer, stagingBuffer, offset, 0, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (method == READBACK_IMMEDIATE) {
|
if (method == READBACK_IMMEDIATE)
|
||||||
|
{
|
||||||
vgfx->submitGpuCommands(false);
|
vgfx->submitGpuCommands(false);
|
||||||
if (stagingBuffer.get()) {
|
if (stagingBuffer.get()) {
|
||||||
status = readbackBuffer(stagingBuffer, 0, size);
|
status = readbackBuffer(stagingBuffer, 0, size);
|
||||||
@@ -36,10 +41,10 @@ GraphicsReadback::GraphicsReadback(love::graphics::Graphics* gfx, ReadbackMethod
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
GraphicsReadback::GraphicsReadback(love::graphics::Graphics* gfx, ReadbackMethod method, love::graphics::Texture* texture, int slice, int mipmap, const Rect& rect, image::ImageData* dest, int destx, int desty)
|
GraphicsReadback::GraphicsReadback(love::graphics::Graphics *gfx, ReadbackMethod method, love::graphics::Texture *texture, int slice, int mipmap, const Rect &rect, image::ImageData *dest, int destx, int desty)
|
||||||
: graphics::GraphicsReadback(gfx, method, texture, slice, mipmap, rect, dest, destx, desty) {
|
: graphics::GraphicsReadback(gfx, method, texture, slice, mipmap, rect, dest, destx, desty)
|
||||||
vgfx = dynamic_cast<Graphics*>(gfx);
|
, vgfx(dynamic_cast<Graphics*>(gfx))
|
||||||
|
{
|
||||||
size_t size = getPixelFormatSliceSize(textureFormat, rect.w, rect.h);
|
size_t size = getPixelFormatSliceSize(textureFormat, rect.w, rect.h);
|
||||||
|
|
||||||
stagingBuffer = vgfx->getTemporaryBuffer(size, DATAFORMAT_FLOAT, 0, BUFFERDATAUSAGE_READBACK);
|
stagingBuffer = vgfx->getTemporaryBuffer(size, DATAFORMAT_FLOAT, 0, BUFFERDATAUSAGE_READBACK);
|
||||||
@@ -57,15 +62,18 @@ GraphicsReadback::GraphicsReadback(love::graphics::Graphics* gfx, ReadbackMethod
|
|||||||
vgfx->submitGpuCommands(false);
|
vgfx->submitGpuCommands(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
GraphicsReadback::~GraphicsReadback() {
|
GraphicsReadback::~GraphicsReadback()
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphicsReadback::wait() {
|
void GraphicsReadback::wait()
|
||||||
|
{
|
||||||
if (status == STATUS_WAITING)
|
if (status == STATUS_WAITING)
|
||||||
vgfx->submitGpuCommands(false);
|
vgfx->submitGpuCommands(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphicsReadback::update() {
|
void GraphicsReadback::update()
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
} // vulkan
|
} // vulkan
|
||||||
|
|||||||
@@ -1,18 +1,21 @@
|
|||||||
#ifndef LOVE_GRAPHICS_VULKAN_GRAPHICS_READBACK_H
|
#pragma once
|
||||||
#define LOVE_GRAPHICS_VULKAN_GRAPHICS_READBACK_H
|
|
||||||
|
|
||||||
#include "graphics/GraphicsReadback.h"
|
#include "graphics/GraphicsReadback.h"
|
||||||
|
|
||||||
namespace love {
|
namespace love
|
||||||
namespace graphics {
|
{
|
||||||
namespace vulkan {
|
namespace graphics
|
||||||
|
{
|
||||||
|
namespace vulkan
|
||||||
|
{
|
||||||
|
|
||||||
class Graphics;
|
class Graphics;
|
||||||
|
|
||||||
class GraphicsReadback : public graphics::GraphicsReadback {
|
class GraphicsReadback : public graphics::GraphicsReadback
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
GraphicsReadback(love::graphics::Graphics* gfx, ReadbackMethod method, love::graphics::Buffer* buffer, size_t offset, size_t size, data::ByteData* dest, size_t destoffset);
|
GraphicsReadback(love::graphics::Graphics *gfx, ReadbackMethod method, love::graphics::Buffer *buffer, size_t offset, size_t size, data::ByteData *dest, size_t destoffset);
|
||||||
GraphicsReadback(love::graphics::Graphics* gfx, ReadbackMethod method, love::graphics::Texture* texture, int slice, int mipmap, const Rect& rect, image::ImageData* dest, int destx, int desty);
|
GraphicsReadback(love::graphics::Graphics *gfx, ReadbackMethod method, love::graphics::Texture *texture, int slice, int mipmap, const Rect &rect, image::ImageData *dest, int destx, int desty);
|
||||||
virtual ~GraphicsReadback();
|
virtual ~GraphicsReadback();
|
||||||
|
|
||||||
void wait() override;
|
void wait() override;
|
||||||
@@ -20,12 +23,10 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Graphics* vgfx;
|
Graphics *vgfx = nullptr;
|
||||||
StrongRef<love::graphics::Buffer> stagingBuffer;
|
StrongRef<love::graphics::Buffer> stagingBuffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // vulkan
|
} // vulkan
|
||||||
} // graphics
|
} // graphics
|
||||||
} // love
|
} // love
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -7,9 +7,13 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace love {
|
namespace love
|
||||||
namespace graphics {
|
{
|
||||||
namespace vulkan {
|
namespace graphics
|
||||||
|
{
|
||||||
|
namespace vulkan
|
||||||
|
{
|
||||||
|
|
||||||
static const TBuiltInResource defaultTBuiltInResource = {
|
static const TBuiltInResource defaultTBuiltInResource = {
|
||||||
/* .MaxLights = */ 32,
|
/* .MaxLights = */ 32,
|
||||||
/* .MaxClipPlanes = */ 6,
|
/* .MaxClipPlanes = */ 6,
|
||||||
@@ -120,8 +124,10 @@ static const TBuiltInResource defaultTBuiltInResource = {
|
|||||||
static const uint32_t STREAMBUFFER_DEFAULT_SIZE = 16;
|
static const uint32_t STREAMBUFFER_DEFAULT_SIZE = 16;
|
||||||
static const uint32_t DESCRIPTOR_POOL_SIZE = 1;
|
static const uint32_t DESCRIPTOR_POOL_SIZE = 1;
|
||||||
|
|
||||||
static VkShaderStageFlagBits getStageBit(ShaderStageType type) {
|
static VkShaderStageFlagBits getStageBit(ShaderStageType type)
|
||||||
switch (type) {
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
case SHADERSTAGE_VERTEX:
|
case SHADERSTAGE_VERTEX:
|
||||||
return VK_SHADER_STAGE_VERTEX_BIT;
|
return VK_SHADER_STAGE_VERTEX_BIT;
|
||||||
case SHADERSTAGE_PIXEL:
|
case SHADERSTAGE_PIXEL:
|
||||||
@@ -133,8 +139,10 @@ static VkShaderStageFlagBits getStageBit(ShaderStageType type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static EShLanguage getGlslShaderType(ShaderStageType stage) {
|
static EShLanguage getGlslShaderType(ShaderStageType stage)
|
||||||
switch (stage) {
|
{
|
||||||
|
switch (stage)
|
||||||
|
{
|
||||||
case SHADERSTAGE_VERTEX:
|
case SHADERSTAGE_VERTEX:
|
||||||
return EShLangVertex;
|
return EShLangVertex;
|
||||||
case SHADERSTAGE_PIXEL:
|
case SHADERSTAGE_PIXEL:
|
||||||
@@ -147,30 +155,30 @@ static EShLanguage getGlslShaderType(ShaderStageType stage) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Shader::Shader(StrongRef<love::graphics::ShaderStage> stages[])
|
Shader::Shader(StrongRef<love::graphics::ShaderStage> stages[])
|
||||||
: graphics::Shader(stages) {
|
: graphics::Shader(stages)
|
||||||
gfx = Module::getInstance<Graphics>(Module::ModuleType::M_GRAPHICS);
|
{
|
||||||
auto vgfx = (Graphics*)gfx;
|
auto gfx = Module::getInstance<Graphics>(Module::ModuleType::M_GRAPHICS);
|
||||||
|
vgfx = dynamic_cast<Graphics*>(gfx);
|
||||||
auto &optionalDeviceFeaures = vgfx->getOptionalDeviceFeatures();
|
auto &optionalDeviceFeaures = vgfx->getOptionalDeviceFeatures();
|
||||||
if (optionalDeviceFeaures.pushDescriptor) {
|
if (optionalDeviceFeaures.pushDescriptor)
|
||||||
pfn_vkCmdPushDescriptorSetKHR = vgfx->getExtensionFunctions().vkCmdPushDescriptorSetKHR;
|
pfn_vkCmdPushDescriptorSetKHR = vgfx->getExtensionFunctions().vkCmdPushDescriptorSetKHR;
|
||||||
}
|
|
||||||
|
|
||||||
loadVolatile();
|
loadVolatile();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Shader::loadVolatile() {
|
bool Shader::loadVolatile()
|
||||||
|
{
|
||||||
computePipeline = VK_NULL_HANDLE;
|
computePipeline = VK_NULL_HANDLE;
|
||||||
|
|
||||||
for (int i = 0; i < BUILTIN_MAX_ENUM; i++) {
|
for (int i = 0; i < BUILTIN_MAX_ENUM; i++)
|
||||||
builtinUniformInfo[i] = nullptr;
|
builtinUniformInfo[i] = nullptr;
|
||||||
}
|
|
||||||
|
|
||||||
compileShaders();
|
compileShaders();
|
||||||
calculateUniformBufferSizeAligned();
|
calculateUniformBufferSizeAligned();
|
||||||
createDescriptorSetLayout();
|
createDescriptorSetLayout();
|
||||||
createPipelineLayout();
|
createPipelineLayout();
|
||||||
createStreamBuffers();
|
createStreamBuffers();
|
||||||
descriptorSetsVector.resize(((Graphics*)gfx)->getNumImagesInFlight());
|
descriptorSetsVector.resize(vgfx->getNumImagesInFlight());
|
||||||
currentFrame = 0;
|
currentFrame = 0;
|
||||||
currentUsedUniformStreamBuffersCount = 0;
|
currentUsedUniformStreamBuffersCount = 0;
|
||||||
currentUsedDescriptorSetsCount = 0;
|
currentUsedDescriptorSetsCount = 0;
|
||||||
@@ -178,19 +186,17 @@ bool Shader::loadVolatile() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shader::unloadVolatile() {
|
void Shader::unloadVolatile()
|
||||||
if (shaderModules.empty()) {
|
{
|
||||||
|
if (shaderModules.empty())
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
auto gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
|
auto gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
|
||||||
gfx->queueCleanUp([shaderModules = std::move(shaderModules), device = device, descriptorSetLayout = descriptorSetLayout, pipelineLayout = pipelineLayout, descriptorPools = descriptorPools, computePipeline = computePipeline](){
|
gfx->queueCleanUp([shaderModules = std::move(shaderModules), device = device, descriptorSetLayout = descriptorSetLayout, pipelineLayout = pipelineLayout, descriptorPools = descriptorPools, computePipeline = computePipeline](){
|
||||||
for (const auto pool : descriptorPools) {
|
for (const auto pool : descriptorPools)
|
||||||
vkDestroyDescriptorPool(device, pool, nullptr);
|
vkDestroyDescriptorPool(device, pool, nullptr);
|
||||||
}
|
for (const auto shaderModule : shaderModules)
|
||||||
for (const auto shaderModule : shaderModules) {
|
|
||||||
vkDestroyShaderModule(device, shaderModule, nullptr);
|
vkDestroyShaderModule(device, shaderModule, nullptr);
|
||||||
}
|
|
||||||
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
|
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
|
||||||
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
|
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
|
||||||
if (computePipeline != VK_NULL_HANDLE)
|
if (computePipeline != VK_NULL_HANDLE)
|
||||||
@@ -211,19 +217,23 @@ void Shader::unloadVolatile() {
|
|||||||
descriptorSetsVector.clear();
|
descriptorSetsVector.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<VkPipelineShaderStageCreateInfo>& Shader::getShaderStages() const {
|
const std::vector<VkPipelineShaderStageCreateInfo>& Shader::getShaderStages() const
|
||||||
|
{
|
||||||
return shaderStages;
|
return shaderStages;
|
||||||
}
|
}
|
||||||
|
|
||||||
const VkPipelineLayout Shader::getGraphicsPipelineLayout() const {
|
const VkPipelineLayout Shader::getGraphicsPipelineLayout() const
|
||||||
|
{
|
||||||
return pipelineLayout;
|
return pipelineLayout;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkPipeline Shader::getComputePipeline() const {
|
VkPipeline Shader::getComputePipeline() const
|
||||||
|
{
|
||||||
return computePipeline;
|
return computePipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
static VkDescriptorImageInfo* createDescriptorImageInfo(graphics::Texture* texture, bool sampler) {
|
static VkDescriptorImageInfo* createDescriptorImageInfo(graphics::Texture* texture, bool sampler)
|
||||||
|
{
|
||||||
auto vkTexture = (Texture*)texture;
|
auto vkTexture = (Texture*)texture;
|
||||||
|
|
||||||
auto imageInfo = new VkDescriptorImageInfo();
|
auto imageInfo = new VkDescriptorImageInfo();
|
||||||
@@ -236,48 +246,52 @@ static VkDescriptorImageInfo* createDescriptorImageInfo(graphics::Texture* textu
|
|||||||
return imageInfo;
|
return imageInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, uint32_t frameIndex, VkPipelineBindPoint bindPoint) {
|
void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, uint32_t frameIndex, VkPipelineBindPoint bindPoint)
|
||||||
|
{
|
||||||
// detect whether a new frame has begun
|
// detect whether a new frame has begun
|
||||||
if (currentFrame != frameIndex) {
|
if (currentFrame != frameIndex)
|
||||||
|
{
|
||||||
currentFrame = frameIndex;
|
currentFrame = frameIndex;
|
||||||
|
|
||||||
currentUsedUniformStreamBuffersCount = 0;
|
currentUsedUniformStreamBuffersCount = 0;
|
||||||
currentUsedDescriptorSetsCount = 0;
|
currentUsedDescriptorSetsCount = 0;
|
||||||
|
|
||||||
// we needed more memory last frame, let's collapse all buffers into a single one.
|
// we needed more memory last frame, let's collapse all buffers into a single one.
|
||||||
if (streamBuffers.at(currentFrame).size() > 1) {
|
if (streamBuffers.at(currentFrame).size() > 1)
|
||||||
|
{
|
||||||
size_t newSize = 0;
|
size_t newSize = 0;
|
||||||
for (auto streamBuffer : streamBuffers.at(currentFrame)) {
|
for (auto streamBuffer : streamBuffers.at(currentFrame))
|
||||||
|
{
|
||||||
newSize += streamBuffer->getSize();
|
newSize += streamBuffer->getSize();
|
||||||
delete streamBuffer;
|
delete streamBuffer;
|
||||||
}
|
}
|
||||||
streamBuffers.at(currentFrame).clear();
|
streamBuffers.at(currentFrame).clear();
|
||||||
streamBuffers.at(currentFrame).push_back(new StreamBuffer(gfx, BUFFERUSAGE_UNIFORM, newSize));
|
streamBuffers.at(currentFrame).push_back(new StreamBuffer(vgfx, BUFFERUSAGE_UNIFORM, newSize));
|
||||||
}
|
}
|
||||||
// no collapse necessary, can just call nextFrame to reset the current (only) streambuffer
|
// no collapse necessary, can just call nextFrame to reset the current (only) streambuffer
|
||||||
else {
|
else
|
||||||
streamBuffers.at(currentFrame).at(0)->nextFrame();
|
streamBuffers.at(currentFrame).at(0)->nextFrame();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// still the same frame
|
// still the same frame
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
auto usedStreamBufferMemory = currentUsedUniformStreamBuffersCount * uniformBufferSizeAligned;
|
auto usedStreamBufferMemory = currentUsedUniformStreamBuffersCount * uniformBufferSizeAligned;
|
||||||
if (usedStreamBufferMemory >= streamBuffers.at(currentFrame).back()->getSize()) {
|
if (usedStreamBufferMemory >= streamBuffers.at(currentFrame).back()->getSize())
|
||||||
|
{
|
||||||
// we ran out of memory in the current frame, need to allocate more.
|
// we ran out of memory in the current frame, need to allocate more.
|
||||||
streamBuffers.at(currentFrame).push_back(new StreamBuffer(gfx, BUFFERUSAGE_UNIFORM, STREAMBUFFER_DEFAULT_SIZE * uniformBufferSizeAligned));
|
streamBuffers.at(currentFrame).push_back(new StreamBuffer(vgfx, BUFFERUSAGE_UNIFORM, STREAMBUFFER_DEFAULT_SIZE * uniformBufferSizeAligned));
|
||||||
currentUsedUniformStreamBuffersCount = 0;
|
currentUsedUniformStreamBuffersCount = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VkDescriptorSet currentDescriptorSet;
|
VkDescriptorSet currentDescriptorSet;
|
||||||
|
|
||||||
if (pfn_vkCmdPushDescriptorSetKHR) {
|
if (pfn_vkCmdPushDescriptorSetKHR)
|
||||||
currentDescriptorSet = 0;
|
currentDescriptorSet = 0;
|
||||||
}
|
else
|
||||||
else {
|
{
|
||||||
if (currentUsedDescriptorSetsCount >= static_cast<uint32_t>(descriptorSetsVector.at(currentFrame).size())) {
|
if (currentUsedDescriptorSetsCount >= static_cast<uint32_t>(descriptorSetsVector.at(currentFrame).size()))
|
||||||
descriptorSetsVector.at(currentFrame).push_back(allocateDescriptorSet());
|
descriptorSetsVector.at(currentFrame).push_back(allocateDescriptorSet());
|
||||||
}
|
|
||||||
|
|
||||||
currentDescriptorSet = descriptorSetsVector.at(currentFrame).at(currentUsedDescriptorSetsCount);
|
currentDescriptorSet = descriptorSetsVector.at(currentFrame).at(currentUsedDescriptorSetsCount);
|
||||||
}
|
}
|
||||||
@@ -350,14 +364,7 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, uint32_t frame
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentDescriptorSet) {
|
if (pfn_vkCmdPushDescriptorSetKHR)
|
||||||
vkUpdateDescriptorSets(device, static_cast<uint32_t>(descriptorWrite.size()), descriptorWrite.data(), 0, nullptr);
|
|
||||||
|
|
||||||
vkCmdBindDescriptorSets(commandBuffer, bindPoint, pipelineLayout, 0, 1, ¤tDescriptorSet, 0, nullptr);
|
|
||||||
|
|
||||||
currentUsedDescriptorSetsCount++;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
pfn_vkCmdPushDescriptorSetKHR(
|
pfn_vkCmdPushDescriptorSetKHR(
|
||||||
commandBuffer,
|
commandBuffer,
|
||||||
bindPoint,
|
bindPoint,
|
||||||
@@ -365,49 +372,63 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, uint32_t frame
|
|||||||
0,
|
0,
|
||||||
static_cast<uint32_t>(descriptorWrite.size()),
|
static_cast<uint32_t>(descriptorWrite.size()),
|
||||||
descriptorWrite.data());
|
descriptorWrite.data());
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vkUpdateDescriptorSets(device, static_cast<uint32_t>(descriptorWrite.size()), descriptorWrite.data(), 0, nullptr);
|
||||||
|
|
||||||
|
vkCmdBindDescriptorSets(commandBuffer, bindPoint, pipelineLayout, 0, 1, ¤tDescriptorSet, 0, nullptr);
|
||||||
|
|
||||||
|
currentUsedDescriptorSetsCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto imageInfo : imageInfos) {
|
for (const auto imageInfo : imageInfos)
|
||||||
delete imageInfo;
|
delete imageInfo;
|
||||||
}
|
if (bufferInfo)
|
||||||
if (bufferInfo) {
|
|
||||||
delete bufferInfo;
|
delete bufferInfo;
|
||||||
}
|
|
||||||
|
|
||||||
currentUsedUniformStreamBuffersCount++;
|
currentUsedUniformStreamBuffersCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
Shader::~Shader() {
|
Shader::~Shader()
|
||||||
|
{
|
||||||
unloadVolatile();
|
unloadVolatile();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shader::attach() {
|
void Shader::attach()
|
||||||
if (!isCompute) {
|
{
|
||||||
if (Shader::current != this) {
|
if (!isCompute)
|
||||||
|
{
|
||||||
|
if (Shader::current != this)
|
||||||
|
{
|
||||||
Graphics::flushBatchedDrawsGlobal();
|
Graphics::flushBatchedDrawsGlobal();
|
||||||
Shader::current = this;
|
Shader::current = this;
|
||||||
Vulkan::shaderSwitch();
|
Vulkan::shaderSwitch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
((Graphics*)gfx)->setComputeShader(this);
|
vgfx->setComputeShader(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Shader::getVertexAttributeIndex(const std::string& name) {
|
int Shader::getVertexAttributeIndex(const std::string& name)
|
||||||
|
{
|
||||||
auto it = attributes.find(name);
|
auto it = attributes.find(name);
|
||||||
return it == attributes.end() ? -1 : it->second;
|
return it == attributes.end() ? -1 : it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Shader::UniformInfo* Shader::getUniformInfo(const std::string& name) const {
|
const Shader::UniformInfo* Shader::getUniformInfo(const std::string& name) const
|
||||||
|
{
|
||||||
return &uniformInfos.at(name);
|
return &uniformInfos.at(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Shader::UniformInfo* Shader::getUniformInfo(BuiltinUniform builtin) const {
|
const Shader::UniformInfo* Shader::getUniformInfo(BuiltinUniform builtin) const
|
||||||
|
{
|
||||||
return builtinUniformInfo[builtin];
|
return builtinUniformInfo[builtin];
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shader::sendTextures(const UniformInfo* info, graphics::Texture** textures, int count) {
|
void Shader::sendTextures(const UniformInfo* info, graphics::Texture** textures, int count)
|
||||||
for (unsigned i = 0; i < count; i++) {
|
{
|
||||||
|
for (unsigned i = 0; i < count; i++)
|
||||||
|
{
|
||||||
auto oldTexture = info->textures[i];
|
auto oldTexture = info->textures[i];
|
||||||
info->textures[i] = textures[i];
|
info->textures[i] = textures[i];
|
||||||
info->textures[i]->retain();
|
info->textures[i]->retain();
|
||||||
@@ -416,8 +437,8 @@ void Shader::sendTextures(const UniformInfo* info, graphics::Texture** textures,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shader::calculateUniformBufferSizeAligned() {
|
void Shader::calculateUniformBufferSizeAligned()
|
||||||
auto vgfx = (Graphics*)gfx;
|
{
|
||||||
auto minAlignment = vgfx->getMinUniformBufferOffsetAlignment();
|
auto minAlignment = vgfx->getMinUniformBufferOffsetAlignment();
|
||||||
size_t size = localUniformStagingData.size();
|
size_t size = localUniformStagingData.size();
|
||||||
auto factor = static_cast<VkDeviceSize>(std::ceil(
|
auto factor = static_cast<VkDeviceSize>(std::ceil(
|
||||||
@@ -426,19 +447,22 @@ void Shader::calculateUniformBufferSizeAligned() {
|
|||||||
uniformBufferSizeAligned = factor * minAlignment;
|
uniformBufferSizeAligned = factor * minAlignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shader::buildLocalUniforms(spirv_cross::Compiler& comp, const spirv_cross::SPIRType& type, size_t baseoff, const std::string& basename) {
|
void Shader::buildLocalUniforms(spirv_cross::Compiler& comp, const spirv_cross::SPIRType &type, size_t baseoff, const std::string &basename)
|
||||||
|
{
|
||||||
using namespace spirv_cross;
|
using namespace spirv_cross;
|
||||||
|
|
||||||
const auto& membertypes = type.member_types;
|
const auto& membertypes = type.member_types;
|
||||||
|
|
||||||
for (size_t uindex = 0; uindex < membertypes.size(); uindex++) {
|
for (size_t uindex = 0; uindex < membertypes.size(); uindex++)
|
||||||
|
{
|
||||||
const auto& memberType = comp.get_type(membertypes[uindex]);
|
const auto& memberType = comp.get_type(membertypes[uindex]);
|
||||||
size_t memberSize = comp.get_declared_struct_member_size(type, uindex);
|
size_t memberSize = comp.get_declared_struct_member_size(type, uindex);
|
||||||
size_t offset = baseoff + comp.type_struct_member_offset(type, uindex);
|
size_t offset = baseoff + comp.type_struct_member_offset(type, uindex);
|
||||||
|
|
||||||
std::string name = basename + comp.get_member_name(type.self, uindex);
|
std::string name = basename + comp.get_member_name(type.self, uindex);
|
||||||
|
|
||||||
switch (memberType.basetype) {
|
switch (memberType.basetype)
|
||||||
|
{
|
||||||
case SPIRType::Struct:
|
case SPIRType::Struct:
|
||||||
name += ".";
|
name += ".";
|
||||||
buildLocalUniforms(comp, memberType, offset, name);
|
buildLocalUniforms(comp, memberType, offset, name);
|
||||||
@@ -458,49 +482,49 @@ void Shader::buildLocalUniforms(spirv_cross::Compiler& comp, const spirv_cross::
|
|||||||
u.components = 1;
|
u.components = 1;
|
||||||
u.data = localUniformStagingData.data() + offset;
|
u.data = localUniformStagingData.data() + offset;
|
||||||
|
|
||||||
if (memberType.columns == 1) {
|
if (memberType.columns == 1)
|
||||||
if (memberType.basetype == SPIRType::Int) {
|
{
|
||||||
|
if (memberType.basetype == SPIRType::Int)
|
||||||
u.baseType = UNIFORM_INT;
|
u.baseType = UNIFORM_INT;
|
||||||
}
|
else if (memberType.basetype == SPIRType::UInt)
|
||||||
else if (memberType.basetype == SPIRType::UInt) {
|
|
||||||
u.baseType = UNIFORM_UINT;
|
u.baseType = UNIFORM_UINT;
|
||||||
}
|
else
|
||||||
else {
|
|
||||||
u.baseType = UNIFORM_FLOAT;
|
u.baseType = UNIFORM_FLOAT;
|
||||||
}
|
|
||||||
u.components = memberType.vecsize;
|
u.components = memberType.vecsize;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
u.baseType = UNIFORM_MATRIX;
|
u.baseType = UNIFORM_MATRIX;
|
||||||
u.matrix.rows = memberType.vecsize;
|
u.matrix.rows = memberType.vecsize;
|
||||||
u.matrix.columns = memberType.columns;
|
u.matrix.columns = memberType.columns;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& reflectionIt = validationReflection.localUniforms.find(u.name);
|
const auto& reflectionIt = validationReflection.localUniforms.find(u.name);
|
||||||
if (reflectionIt != validationReflection.localUniforms.end()) {
|
if (reflectionIt != validationReflection.localUniforms.end())
|
||||||
|
{
|
||||||
const auto& localUniform = reflectionIt->second;
|
const auto& localUniform = reflectionIt->second;
|
||||||
const auto& values = localUniform.initializerValues;
|
const auto& values = localUniform.initializerValues;
|
||||||
if (!values.empty()) {
|
if (!values.empty())
|
||||||
memcpy(
|
memcpy(
|
||||||
u.data,
|
u.data,
|
||||||
values.data(),
|
values.data(),
|
||||||
std::min(u.dataSize, values.size() * sizeof(LocalUniformValue)));
|
std::min(u.dataSize, values.size() * sizeof(LocalUniformValue)));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uniformInfos[u.name] = u;
|
uniformInfos[u.name] = u;
|
||||||
|
|
||||||
BuiltinUniform builtin = BUILTIN_MAX_ENUM;
|
BuiltinUniform builtin = BUILTIN_MAX_ENUM;
|
||||||
if (getConstant(u.name.c_str(), builtin)) {
|
if (getConstant(u.name.c_str(), builtin))
|
||||||
if (builtin == BUILTIN_UNIFORMS_PER_DRAW) {
|
{
|
||||||
|
if (builtin == BUILTIN_UNIFORMS_PER_DRAW)
|
||||||
builtinUniformDataOffset = offset;
|
builtinUniformDataOffset = offset;
|
||||||
}
|
|
||||||
builtinUniformInfo[builtin] = &uniformInfos[u.name];
|
builtinUniformInfo[builtin] = &uniformInfos[u.name];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shader::compileShaders() {
|
void Shader::compileShaders()
|
||||||
|
{
|
||||||
using namespace glslang;
|
using namespace glslang;
|
||||||
using namespace spirv_cross;
|
using namespace spirv_cross;
|
||||||
|
|
||||||
@@ -508,11 +532,10 @@ void Shader::compileShaders() {
|
|||||||
|
|
||||||
auto program = new TProgram();
|
auto program = new TProgram();
|
||||||
|
|
||||||
gfx = Module::getInstance<Graphics>(Module::ModuleType::M_GRAPHICS);
|
|
||||||
auto vgfx = (Graphics*)gfx;
|
|
||||||
device = vgfx->getDevice();
|
device = vgfx->getDevice();
|
||||||
|
|
||||||
for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++) {
|
for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++)
|
||||||
|
{
|
||||||
if (!stages[i])
|
if (!stages[i])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -543,7 +566,8 @@ void Shader::compileShaders() {
|
|||||||
bool forceDefault = false;
|
bool forceDefault = false;
|
||||||
bool forwardCompat = true;
|
bool forwardCompat = true;
|
||||||
|
|
||||||
if (!tshader->parse(&defaultTBuiltInResource, defaultVersion, defaultProfile, forceDefault, forwardCompat, EShMsgSuppressWarnings)) {
|
if (!tshader->parse(&defaultTBuiltInResource, defaultVersion, defaultProfile, forceDefault, forwardCompat, EShMsgSuppressWarnings))
|
||||||
|
{
|
||||||
const char* msg1 = tshader->getInfoLog();
|
const char* msg1 = tshader->getInfoLog();
|
||||||
const char* msg2 = tshader->getInfoDebugLog();
|
const char* msg2 = tshader->getInfoDebugLog();
|
||||||
|
|
||||||
@@ -554,17 +578,16 @@ void Shader::compileShaders() {
|
|||||||
glslangShaders.push_back(tshader);
|
glslangShaders.push_back(tshader);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!program->link(EShMsgDefault)) {
|
if (!program->link(EShMsgDefault))
|
||||||
throw love::Exception("link failed! %s\n", program->getInfoLog());
|
throw love::Exception("link failed! %s\n", program->getInfoLog());
|
||||||
}
|
|
||||||
|
|
||||||
if (!program->mapIO()) {
|
if (!program->mapIO())
|
||||||
throw love::Exception("mapIO failed");
|
throw love::Exception("mapIO failed");
|
||||||
}
|
|
||||||
|
|
||||||
uniformInfos.clear();
|
uniformInfos.clear();
|
||||||
|
|
||||||
for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++) {
|
for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++)
|
||||||
|
{
|
||||||
auto shaderStage = (ShaderStageType)i;
|
auto shaderStage = (ShaderStageType)i;
|
||||||
auto glslangStage = getGlslShaderType(shaderStage);
|
auto glslangStage = getGlslShaderType(shaderStage);
|
||||||
auto intermediate = program->getIntermediate(glslangStage);
|
auto intermediate = program->getIntermediate(glslangStage);
|
||||||
@@ -586,8 +609,7 @@ void Shader::compileShaders() {
|
|||||||
createInfo.codeSize = spirv.size() * sizeof(uint32_t);
|
createInfo.codeSize = spirv.size() * sizeof(uint32_t);
|
||||||
createInfo.pCode = spirv.data();
|
createInfo.pCode = spirv.data();
|
||||||
|
|
||||||
Graphics* vkGfx = (Graphics*)gfx;
|
auto device = vgfx->getDevice();
|
||||||
auto device = vkGfx->getDevice();
|
|
||||||
|
|
||||||
VkShaderModule shaderModule;
|
VkShaderModule shaderModule;
|
||||||
|
|
||||||
@@ -612,8 +634,10 @@ void Shader::compileShaders() {
|
|||||||
auto shaderResources = comp.get_shader_resources(active);
|
auto shaderResources = comp.get_shader_resources(active);
|
||||||
comp.set_enabled_interface_variables(std::move(active));
|
comp.set_enabled_interface_variables(std::move(active));
|
||||||
|
|
||||||
for (const auto& resource : shaderResources.uniform_buffers) {
|
for (const auto& resource : shaderResources.uniform_buffers)
|
||||||
if (resource.name == "gl_DefaultUniformBlock") {
|
{
|
||||||
|
if (resource.name == "gl_DefaultUniformBlock")
|
||||||
|
{
|
||||||
const auto& type = comp.get_type(resource.base_type_id);
|
const auto& type = comp.get_type(resource.base_type_id);
|
||||||
size_t uniformBufferObjectSize = comp.get_declared_struct_size(type);
|
size_t uniformBufferObjectSize = comp.get_declared_struct_size(type);
|
||||||
auto defaultUniformBlockSize = comp.get_declared_struct_size(type);
|
auto defaultUniformBlockSize = comp.get_declared_struct_size(type);
|
||||||
@@ -625,12 +649,12 @@ void Shader::compileShaders() {
|
|||||||
std::string basename("");
|
std::string basename("");
|
||||||
buildLocalUniforms(comp, type, 0, basename);
|
buildLocalUniforms(comp, type, 0, basename);
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
throw love::Exception("unimplemented: non default uniform blocks.");
|
throw love::Exception("unimplemented: non default uniform blocks.");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& r : shaderResources.sampled_images) {
|
for (const auto& r : shaderResources.sampled_images)
|
||||||
|
{
|
||||||
const SPIRType& basetype = comp.get_type(r.base_type_id);
|
const SPIRType& basetype = comp.get_type(r.base_type_id);
|
||||||
const SPIRType& type = comp.get_type(r.type_id);
|
const SPIRType& type = comp.get_type(r.type_id);
|
||||||
const SPIRType& imagetype = comp.get_type(basetype.image.type);
|
const SPIRType& imagetype = comp.get_type(basetype.image.type);
|
||||||
@@ -643,7 +667,8 @@ void Shader::compileShaders() {
|
|||||||
info.isDepthSampler = type.image.depth;
|
info.isDepthSampler = type.image.depth;
|
||||||
info.components = 1;
|
info.components = 1;
|
||||||
|
|
||||||
switch (imagetype.basetype) {
|
switch (imagetype.basetype)
|
||||||
|
{
|
||||||
case SPIRType::Float:
|
case SPIRType::Float:
|
||||||
info.dataBaseType = DATA_BASETYPE_FLOAT;
|
info.dataBaseType = DATA_BASETYPE_FLOAT;
|
||||||
break;
|
break;
|
||||||
@@ -657,7 +682,8 @@ void Shader::compileShaders() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (basetype.image.dim) {
|
switch (basetype.image.dim)
|
||||||
|
{
|
||||||
case spv::Dim2D:
|
case spv::Dim2D:
|
||||||
info.textureType = basetype.image.arrayed ? TEXTURE_2D_ARRAY : TEXTURE_2D;
|
info.textureType = basetype.image.arrayed ? TEXTURE_2D_ARRAY : TEXTURE_2D;
|
||||||
info.textures = new love::graphics::Texture * [info.count];
|
info.textures = new love::graphics::Texture * [info.count];
|
||||||
@@ -679,7 +705,8 @@ void Shader::compileShaders() {
|
|||||||
throw love::Exception("unknown dim");
|
throw love::Exception("unknown dim");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.baseType == UNIFORM_SAMPLER) {
|
if (info.baseType == UNIFORM_SAMPLER)
|
||||||
|
{
|
||||||
auto tex = vgfx->getDefaultTexture();
|
auto tex = vgfx->getDefaultTexture();
|
||||||
for (int i = 0; i < info.count; i++) {
|
for (int i = 0; i < info.count; i++) {
|
||||||
info.textures[i] = tex;
|
info.textures[i] = tex;
|
||||||
@@ -687,18 +714,17 @@ void Shader::compileShaders() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// fixme
|
// fixme
|
||||||
else if (info.baseType == UNIFORM_TEXELBUFFER) {
|
else if (info.baseType == UNIFORM_TEXELBUFFER)
|
||||||
throw love::Exception("texel buffers not supported yet");
|
throw love::Exception("texel buffers not supported yet");
|
||||||
}
|
|
||||||
|
|
||||||
uniformInfos[r.name] = info;
|
uniformInfos[r.name] = info;
|
||||||
BuiltinUniform builtin;
|
BuiltinUniform builtin;
|
||||||
if (getConstant(r.name.c_str(), builtin)) {
|
if (getConstant(r.name.c_str(), builtin))
|
||||||
builtinUniformInfo[builtin] = &uniformInfos[info.name];
|
builtinUniformInfo[builtin] = &uniformInfos[info.name];
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& r : shaderResources.storage_buffers) {
|
for (const auto& r : shaderResources.storage_buffers)
|
||||||
|
{
|
||||||
const auto& type = comp.get_type(r.type_id);
|
const auto& type = comp.get_type(r.type_id);
|
||||||
|
|
||||||
UniformInfo u{};
|
UniformInfo u{};
|
||||||
@@ -709,27 +735,27 @@ void Shader::compileShaders() {
|
|||||||
u.location = comp.get_decoration(r.id, spv::DecorationBinding);
|
u.location = comp.get_decoration(r.id, spv::DecorationBinding);
|
||||||
|
|
||||||
const auto reflectionit = validationReflection.storageBuffers.find(u.name);
|
const auto reflectionit = validationReflection.storageBuffers.find(u.name);
|
||||||
if (reflectionit != validationReflection.storageBuffers.end()) {
|
if (reflectionit != validationReflection.storageBuffers.end())
|
||||||
|
{
|
||||||
u.bufferStride = reflectionit->second.stride;
|
u.bufferStride = reflectionit->second.stride;
|
||||||
u.bufferMemberCount = reflectionit->second.memberCount;
|
u.bufferMemberCount = reflectionit->second.memberCount;
|
||||||
u.access = reflectionit->second.access;
|
u.access = reflectionit->second.access;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
// todo: some stuff missing
|
// todo: some stuff missing
|
||||||
|
|
||||||
u.buffers = new love::graphics::Buffer * [u.count];
|
u.buffers = new love::graphics::Buffer * [u.count];
|
||||||
|
|
||||||
for (int i = 0; i < u.count; i++) {
|
for (int i = 0; i < u.count; i++)
|
||||||
u.buffers[i] = nullptr;
|
u.buffers[i] = nullptr;
|
||||||
}
|
|
||||||
|
|
||||||
uniformInfos[u.name] = u;
|
uniformInfos[u.name] = u;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& r : shaderResources.storage_images) {
|
for (const auto& r : shaderResources.storage_images)
|
||||||
|
{
|
||||||
const auto& type = comp.get_type(r.type_id);
|
const auto& type = comp.get_type(r.type_id);
|
||||||
|
|
||||||
UniformInfo u{};
|
UniformInfo u{};
|
||||||
@@ -740,53 +766,53 @@ void Shader::compileShaders() {
|
|||||||
u.textures = new love::graphics::Texture * [u.count];
|
u.textures = new love::graphics::Texture * [u.count];
|
||||||
u.location = comp.get_decoration(r.id, spv::DecorationBinding);
|
u.location = comp.get_decoration(r.id, spv::DecorationBinding);
|
||||||
|
|
||||||
for (int i = 0; i < u.count; i++) {
|
for (int i = 0; i < u.count; i++)
|
||||||
u.textures[i] = nullptr;
|
u.textures[i] = nullptr;
|
||||||
}
|
|
||||||
|
|
||||||
// some stuff missing ?
|
// some stuff missing ?
|
||||||
|
|
||||||
uniformInfos[u.name] = u;
|
uniformInfos[u.name] = u;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shaderStage == SHADERSTAGE_VERTEX) {
|
if (shaderStage == SHADERSTAGE_VERTEX)
|
||||||
for (const auto& r : shaderResources.stage_inputs) {
|
for (const auto& r : shaderResources.stage_inputs)
|
||||||
|
{
|
||||||
const auto& name = r.name;
|
const auto& name = r.name;
|
||||||
const int attributeLocation = static_cast<int>(comp.get_decoration(r.id, spv::DecorationLocation));
|
const int attributeLocation = static_cast<int>(comp.get_decoration(r.id, spv::DecorationLocation));
|
||||||
attributes[name] = attributeLocation;
|
attributes[name] = attributeLocation;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete program;
|
delete program;
|
||||||
for (auto shader : glslangShaders) {
|
for (auto shader : glslangShaders)
|
||||||
delete shader;
|
delete shader;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shader::createDescriptorSetLayout() {
|
void Shader::createDescriptorSetLayout()
|
||||||
|
{
|
||||||
std::vector<VkDescriptorSetLayoutBinding> bindings;
|
std::vector<VkDescriptorSetLayoutBinding> bindings;
|
||||||
|
|
||||||
for (auto const& [key, val] : uniformInfos) {
|
for (auto const& [key, val] : uniformInfos)
|
||||||
|
{
|
||||||
auto type = Vulkan::getDescriptorType(val.baseType);
|
auto type = Vulkan::getDescriptorType(val.baseType);
|
||||||
if (type != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) {
|
if (type != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER)
|
||||||
|
{
|
||||||
VkDescriptorSetLayoutBinding layoutBinding{};
|
VkDescriptorSetLayoutBinding layoutBinding{};
|
||||||
|
|
||||||
layoutBinding.binding = val.location;
|
layoutBinding.binding = val.location;
|
||||||
layoutBinding.descriptorType = type;
|
layoutBinding.descriptorType = type;
|
||||||
layoutBinding.descriptorCount = val.count;
|
layoutBinding.descriptorCount = val.count;
|
||||||
if (isCompute) {
|
if (isCompute)
|
||||||
layoutBinding.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
|
layoutBinding.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
|
||||||
}
|
else
|
||||||
else {
|
|
||||||
layoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
|
layoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
}
|
|
||||||
|
|
||||||
bindings.push_back(layoutBinding);
|
bindings.push_back(layoutBinding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!localUniformStagingData.empty()) {
|
if (!localUniformStagingData.empty())
|
||||||
|
{
|
||||||
VkDescriptorSetLayoutBinding uniformBinding{};
|
VkDescriptorSetLayoutBinding uniformBinding{};
|
||||||
uniformBinding.binding = uniformLocation;
|
uniformBinding.binding = uniformLocation;
|
||||||
uniformBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
uniformBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||||
@@ -805,23 +831,23 @@ void Shader::createDescriptorSetLayout() {
|
|||||||
if (pfn_vkCmdPushDescriptorSetKHR)
|
if (pfn_vkCmdPushDescriptorSetKHR)
|
||||||
layoutInfo.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
|
layoutInfo.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
|
||||||
|
|
||||||
if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout) != VK_SUCCESS) {
|
if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout) != VK_SUCCESS)
|
||||||
throw love::Exception("failed to create descriptor set layout");
|
throw love::Exception("failed to create descriptor set layout");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shader::createPipelineLayout() {
|
void Shader::createPipelineLayout()
|
||||||
|
{
|
||||||
VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
|
VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
|
||||||
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||||
pipelineLayoutInfo.setLayoutCount = 1;
|
pipelineLayoutInfo.setLayoutCount = 1;
|
||||||
pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout;
|
pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout;
|
||||||
pipelineLayoutInfo.pushConstantRangeCount = 0;
|
pipelineLayoutInfo.pushConstantRangeCount = 0;
|
||||||
|
|
||||||
if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) {
|
if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS)
|
||||||
throw love::Exception("failed to create pipeline layout");
|
throw love::Exception("failed to create pipeline layout");
|
||||||
}
|
|
||||||
|
|
||||||
if (isCompute) {
|
if (isCompute)
|
||||||
|
{
|
||||||
assert(shaderStages.size() == 1);
|
assert(shaderStages.size() == 1);
|
||||||
|
|
||||||
VkComputePipelineCreateInfo computeInfo{};
|
VkComputePipelineCreateInfo computeInfo{};
|
||||||
@@ -829,38 +855,39 @@ void Shader::createPipelineLayout() {
|
|||||||
computeInfo.stage = shaderStages.at(0);
|
computeInfo.stage = shaderStages.at(0);
|
||||||
computeInfo.layout = pipelineLayout;
|
computeInfo.layout = pipelineLayout;
|
||||||
|
|
||||||
if (vkCreateComputePipelines(device, VK_NULL_HANDLE, 1, &computeInfo, nullptr, &computePipeline) != VK_SUCCESS) {
|
if (vkCreateComputePipelines(device, VK_NULL_HANDLE, 1, &computeInfo, nullptr, &computePipeline) != VK_SUCCESS)
|
||||||
throw love::Exception("failed to create compute pipeline");
|
throw love::Exception("failed to create compute pipeline");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shader::createStreamBuffers() {
|
void Shader::createStreamBuffers()
|
||||||
auto vgfx = (Graphics*)gfx;
|
{
|
||||||
const auto numImagesInFlight = vgfx->getNumImagesInFlight();
|
const auto numImagesInFlight = vgfx->getNumImagesInFlight();
|
||||||
streamBuffers.resize(numImagesInFlight);
|
streamBuffers.resize(numImagesInFlight);
|
||||||
for (uint32_t i = 0; i < numImagesInFlight; i++) {
|
for (uint32_t i = 0; i < numImagesInFlight; i++)
|
||||||
streamBuffers[i].push_back(new StreamBuffer(gfx, BUFFERUSAGE_UNIFORM, STREAMBUFFER_DEFAULT_SIZE * uniformBufferSizeAligned));
|
streamBuffers[i].push_back(new StreamBuffer(vgfx, BUFFERUSAGE_UNIFORM, STREAMBUFFER_DEFAULT_SIZE * uniformBufferSizeAligned));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shader::setVideoTextures(graphics::Texture* ytexture, graphics::Texture* cbtexture, graphics::Texture* crtexture) {
|
void Shader::setVideoTextures(graphics::Texture* ytexture, graphics::Texture* cbtexture, graphics::Texture* crtexture)
|
||||||
|
{
|
||||||
// if the shader doesn't actually use these textures they might get optimized out
|
// if the shader doesn't actually use these textures they might get optimized out
|
||||||
// in that case this function becomes a noop.
|
// in that case this function becomes a noop.
|
||||||
if (builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_Y] != nullptr) {
|
if (builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_Y] != nullptr)
|
||||||
|
{
|
||||||
auto oldTexture = builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_Y]->textures[0];
|
auto oldTexture = builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_Y]->textures[0];
|
||||||
ytexture->retain();
|
ytexture->retain();
|
||||||
oldTexture->release();
|
oldTexture->release();
|
||||||
builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_Y]->textures[0] = ytexture;
|
builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_Y]->textures[0] = ytexture;
|
||||||
|
|
||||||
}
|
}
|
||||||
if (builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CB] != nullptr) {
|
if (builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CB] != nullptr)
|
||||||
|
{
|
||||||
auto oldTexture = builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CB]->textures[0];
|
auto oldTexture = builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CB]->textures[0];
|
||||||
cbtexture->retain();
|
cbtexture->retain();
|
||||||
oldTexture->release();
|
oldTexture->release();
|
||||||
builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CB]->textures[0] = cbtexture;
|
builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CB]->textures[0] = cbtexture;
|
||||||
}
|
}
|
||||||
if (builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CR] != nullptr) {
|
if (builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CR] != nullptr)
|
||||||
|
{
|
||||||
auto oldTexture = builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CR]->textures[0];
|
auto oldTexture = builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CR]->textures[0];
|
||||||
crtexture->retain();
|
crtexture->retain();
|
||||||
oldTexture->release();
|
oldTexture->release();
|
||||||
@@ -868,19 +895,23 @@ void Shader::setVideoTextures(graphics::Texture* ytexture, graphics::Texture* cb
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Shader::hasUniform(const std::string& name) const {
|
bool Shader::hasUniform(const std::string& name) const
|
||||||
|
{
|
||||||
return uniformInfos.find(name) != uniformInfos.end();
|
return uniformInfos.find(name) != uniformInfos.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shader::setUniformData(BuiltinUniformData& data) {
|
void Shader::setUniformData(BuiltinUniformData& data)
|
||||||
|
{
|
||||||
char* ptr = (char*) builtinUniformInfo[BUILTIN_UNIFORMS_PER_DRAW]->data + builtinUniformDataOffset;
|
char* ptr = (char*) builtinUniformInfo[BUILTIN_UNIFORMS_PER_DRAW]->data + builtinUniformDataOffset;
|
||||||
memcpy(ptr, &data, sizeof(BuiltinUniformData));
|
memcpy(ptr, &data, sizeof(BuiltinUniformData));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shader::setMainTex(graphics::Texture* texture) {
|
void Shader::setMainTex(graphics::Texture* texture)
|
||||||
|
{
|
||||||
// if the shader doesn't actually use the texture it might get optimized out
|
// if the shader doesn't actually use the texture it might get optimized out
|
||||||
// in that case this function becomes a noop.
|
// in that case this function becomes a noop.
|
||||||
if (builtinUniformInfo[BUILTIN_TEXTURE_MAIN] != nullptr) {
|
if (builtinUniformInfo[BUILTIN_TEXTURE_MAIN] != nullptr)
|
||||||
|
{
|
||||||
auto oldTexture = builtinUniformInfo[BUILTIN_TEXTURE_MAIN]->textures[0];
|
auto oldTexture = builtinUniformInfo[BUILTIN_TEXTURE_MAIN]->textures[0];
|
||||||
texture->retain();
|
texture->retain();
|
||||||
oldTexture->release();
|
oldTexture->release();
|
||||||
@@ -888,8 +919,10 @@ void Shader::setMainTex(graphics::Texture* texture) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VkDescriptorSet Shader::allocateDescriptorSet() {
|
VkDescriptorSet Shader::allocateDescriptorSet()
|
||||||
if (freeDescriptorSets.empty()) {
|
{
|
||||||
|
if (freeDescriptorSets.empty())
|
||||||
|
{
|
||||||
// fixme: we can optimize this, since sizes should never change for a given shader.
|
// fixme: we can optimize this, since sizes should never change for a given shader.
|
||||||
std::vector<VkDescriptorPoolSize> sizes;
|
std::vector<VkDescriptorPoolSize> sizes;
|
||||||
|
|
||||||
@@ -899,7 +932,8 @@ VkDescriptorSet Shader::allocateDescriptorSet() {
|
|||||||
|
|
||||||
sizes.push_back(size);
|
sizes.push_back(size);
|
||||||
|
|
||||||
for (const auto& [key, val] : uniformInfos) {
|
for (const auto& [key, val] : uniformInfos)
|
||||||
|
{
|
||||||
VkDescriptorPoolSize size{};
|
VkDescriptorPoolSize size{};
|
||||||
auto type = Vulkan::getDescriptorType(val.baseType);
|
auto type = Vulkan::getDescriptorType(val.baseType);
|
||||||
if (type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) {
|
if (type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) {
|
||||||
@@ -917,9 +951,8 @@ VkDescriptorSet Shader::allocateDescriptorSet() {
|
|||||||
createInfo.pPoolSizes = sizes.data();
|
createInfo.pPoolSizes = sizes.data();
|
||||||
|
|
||||||
VkDescriptorPool pool;
|
VkDescriptorPool pool;
|
||||||
if (vkCreateDescriptorPool(device, &createInfo, nullptr, &pool) != VK_SUCCESS) {
|
if (vkCreateDescriptorPool(device, &createInfo, nullptr, &pool) != VK_SUCCESS)
|
||||||
throw love::Exception("failed to create descriptor pool");
|
throw love::Exception("failed to create descriptor pool");
|
||||||
}
|
|
||||||
descriptorPools.push_back(pool);
|
descriptorPools.push_back(pool);
|
||||||
|
|
||||||
std::vector<VkDescriptorSetLayout> layouts(DESCRIPTOR_POOL_SIZE, descriptorSetLayout);
|
std::vector<VkDescriptorSetLayout> layouts(DESCRIPTOR_POOL_SIZE, descriptorSetLayout);
|
||||||
@@ -933,19 +966,18 @@ VkDescriptorSet Shader::allocateDescriptorSet() {
|
|||||||
std::vector<VkDescriptorSet> descriptorSet;
|
std::vector<VkDescriptorSet> descriptorSet;
|
||||||
descriptorSet.resize(DESCRIPTOR_POOL_SIZE);
|
descriptorSet.resize(DESCRIPTOR_POOL_SIZE);
|
||||||
VkResult result = vkAllocateDescriptorSets(device, &allocInfo, descriptorSet.data());
|
VkResult result = vkAllocateDescriptorSets(device, &allocInfo, descriptorSet.data());
|
||||||
if (result != VK_SUCCESS) {
|
if (result != VK_SUCCESS)
|
||||||
throw love::Exception("failed to allocate descriptor set");
|
throw love::Exception("failed to allocate descriptor set");
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto ds : descriptorSet) {
|
for (const auto ds : descriptorSet)
|
||||||
freeDescriptorSets.push(ds);
|
freeDescriptorSets.push(ds);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ds = freeDescriptorSets.front();
|
auto ds = freeDescriptorSets.front();
|
||||||
freeDescriptorSets.pop();
|
freeDescriptorSets.pop();
|
||||||
return ds;
|
return ds;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // vulkan
|
} // vulkan
|
||||||
} // graphics
|
} // graphics
|
||||||
} // love
|
} // love
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
#ifndef LOVE_GRAPHICS_VULKAN_SHADER_H
|
#pragma once
|
||||||
#define LOVE_GRAPHICS_VULKAN_SHADER_H
|
|
||||||
|
|
||||||
|
// LÖVE
|
||||||
#include <graphics/Shader.h>
|
#include <graphics/Shader.h>
|
||||||
#include <graphics/vulkan/ShaderStage.h>
|
#include <graphics/vulkan/ShaderStage.h>
|
||||||
#include "Vulkan.h"
|
#include "Vulkan.h"
|
||||||
|
|
||||||
|
// Libraries
|
||||||
#include "VulkanWrapper.h"
|
#include "VulkanWrapper.h"
|
||||||
#include "libraries/spirv_cross/spirv_reflect.hpp"
|
#include "libraries/spirv_cross/spirv_reflect.hpp"
|
||||||
|
|
||||||
|
// C++
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -15,10 +17,19 @@
|
|||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
|
|
||||||
namespace love {
|
namespace love
|
||||||
namespace graphics {
|
{
|
||||||
namespace vulkan {
|
namespace graphics
|
||||||
class Shader final : public graphics::Shader, public Volatile {
|
{
|
||||||
|
namespace vulkan
|
||||||
|
{
|
||||||
|
|
||||||
|
class Graphics;
|
||||||
|
|
||||||
|
class Shader final
|
||||||
|
: public graphics::Shader
|
||||||
|
, public Volatile
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
Shader(StrongRef<love::graphics::ShaderStage> stages[]);
|
Shader(StrongRef<love::graphics::ShaderStage> stages[]);
|
||||||
virtual ~Shader();
|
virtual ~Shader();
|
||||||
@@ -94,7 +105,8 @@ private:
|
|||||||
|
|
||||||
std::vector<VkPipelineShaderStageCreateInfo> shaderStages;
|
std::vector<VkPipelineShaderStageCreateInfo> shaderStages;
|
||||||
std::vector<VkShaderModule> shaderModules;
|
std::vector<VkShaderModule> shaderModules;
|
||||||
Graphics* gfx;
|
|
||||||
|
Graphics *vgfx = nullptr;
|
||||||
VkDevice device;
|
VkDevice device;
|
||||||
|
|
||||||
bool isCompute = false;
|
bool isCompute = false;
|
||||||
@@ -113,8 +125,7 @@ private:
|
|||||||
uint32_t currentUsedUniformStreamBuffersCount;
|
uint32_t currentUsedUniformStreamBuffersCount;
|
||||||
uint32_t currentUsedDescriptorSetsCount;
|
uint32_t currentUsedDescriptorSetsCount;
|
||||||
};
|
};
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,23 +1,29 @@
|
|||||||
#include "ShaderStage.h"
|
#include "ShaderStage.h"
|
||||||
|
|
||||||
#include "Graphics.h"
|
#include "Graphics.h"
|
||||||
|
|
||||||
#include "libraries/glslang/glslang/Public/ShaderLang.h"
|
#include "libraries/glslang/glslang/Public/ShaderLang.h"
|
||||||
#include "libraries/glslang/SPIRV/GlslangToSpv.h"
|
#include "libraries/glslang/SPIRV/GlslangToSpv.h"
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
|
namespace love
|
||||||
|
{
|
||||||
|
namespace graphics
|
||||||
|
{
|
||||||
|
namespace vulkan
|
||||||
|
{
|
||||||
|
|
||||||
namespace love {
|
ShaderStage::ShaderStage(love::graphics::Graphics *gfx, ShaderStageType stage, const std::string &glsl, bool gles, const std::string &cachekey)
|
||||||
namespace graphics {
|
|
||||||
namespace vulkan {
|
|
||||||
ShaderStage::ShaderStage(love::graphics::Graphics* gfx, ShaderStageType stage, const std::string& glsl, bool gles, const std::string& cachekey)
|
|
||||||
: love::graphics::ShaderStage(gfx, stage, glsl, gles, cachekey) {
|
: love::graphics::ShaderStage(gfx, stage, glsl, gles, cachekey) {
|
||||||
// the compilation is done in Shader.
|
// the compilation is done in Shader.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ptrdiff_t ShaderStage::getHandle() const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
} // love
|
} // love
|
||||||
} // graphics
|
} // graphics
|
||||||
} // vulkan
|
} // vulkan
|
||||||
|
|||||||
@@ -1,24 +1,25 @@
|
|||||||
#ifndef LOVE_GRAPHICS_VULKAN_SHADERSTAGE_H
|
#pragma once
|
||||||
#define LOVE_GRAPHICS_VULKAN_SHADERSTAGE_H
|
|
||||||
|
|
||||||
#include "graphics/ShaderStage.h"
|
#include "graphics/ShaderStage.h"
|
||||||
#include "modules/graphics/Graphics.h"
|
#include "modules/graphics/Graphics.h"
|
||||||
|
|
||||||
#include "VulkanWrapper.h"
|
#include "VulkanWrapper.h"
|
||||||
|
|
||||||
namespace love {
|
namespace love
|
||||||
namespace graphics {
|
{
|
||||||
namespace vulkan {
|
namespace graphics
|
||||||
class ShaderStage final : public graphics::ShaderStage {
|
{
|
||||||
|
namespace vulkan
|
||||||
|
{
|
||||||
|
|
||||||
|
class ShaderStage final : public graphics::ShaderStage
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
ShaderStage(love::graphics::Graphics* gfx, ShaderStageType stage, const std::string& glsl, bool gles, const std::string& cachekey);
|
ShaderStage(love::graphics::Graphics *gfx, ShaderStageType stage, const std::string &glsl, bool gles, const std::string &cachekey);
|
||||||
|
|
||||||
ptrdiff_t getHandle() const {
|
ptrdiff_t getHandle() const override;
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,11 +3,17 @@
|
|||||||
#include "Graphics.h"
|
#include "Graphics.h"
|
||||||
|
|
||||||
|
|
||||||
namespace love {
|
namespace love
|
||||||
namespace graphics {
|
{
|
||||||
namespace vulkan {
|
namespace graphics
|
||||||
static VkBufferUsageFlags getUsageFlags(BufferUsage mode) {
|
{
|
||||||
switch (mode) {
|
namespace vulkan
|
||||||
|
{
|
||||||
|
|
||||||
|
static VkBufferUsageFlags getUsageFlags(BufferUsage mode)
|
||||||
|
{
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
case BUFFERUSAGE_VERTEX: return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
|
case BUFFERUSAGE_VERTEX: return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
|
||||||
case BUFFERUSAGE_INDEX: return VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
|
case BUFFERUSAGE_INDEX: return VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
|
||||||
case BUFFERUSAGE_UNIFORM: return VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
|
case BUFFERUSAGE_UNIFORM: return VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
|
||||||
@@ -16,13 +22,15 @@ static VkBufferUsageFlags getUsageFlags(BufferUsage mode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StreamBuffer::StreamBuffer(graphics::Graphics* gfx, BufferUsage mode, size_t size)
|
StreamBuffer::StreamBuffer(graphics::Graphics *gfx, BufferUsage mode, size_t size)
|
||||||
: love::graphics::StreamBuffer(mode, size), gfx(gfx) {
|
: love::graphics::StreamBuffer(mode, size)
|
||||||
|
, vgfx(dynamic_cast<Graphics*>(gfx))
|
||||||
|
{
|
||||||
loadVolatile();
|
loadVolatile();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StreamBuffer::loadVolatile() {
|
bool StreamBuffer::loadVolatile()
|
||||||
Graphics* vgfx = (Graphics*)gfx;
|
{
|
||||||
allocator = vgfx->getVmaAllocator();
|
allocator = vgfx->getVmaAllocator();
|
||||||
|
|
||||||
VkBufferCreateInfo bufferInfo{};
|
VkBufferCreateInfo bufferInfo{};
|
||||||
@@ -42,37 +50,48 @@ bool StreamBuffer::loadVolatile() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamBuffer::unloadVolatile() {
|
void StreamBuffer::unloadVolatile()
|
||||||
|
{
|
||||||
if (buffer == VK_NULL_HANDLE)
|
if (buffer == VK_NULL_HANDLE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto vgfx = (Graphics*)gfx;
|
|
||||||
vgfx->queueCleanUp([allocator=allocator, buffer=buffer, allocation=allocation](){
|
vgfx->queueCleanUp([allocator=allocator, buffer=buffer, allocation=allocation](){
|
||||||
vmaDestroyBuffer(allocator, buffer, allocation);
|
vmaDestroyBuffer(allocator, buffer, allocation);
|
||||||
});
|
});
|
||||||
buffer = VK_NULL_HANDLE;
|
buffer = VK_NULL_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
StreamBuffer::~StreamBuffer() {
|
StreamBuffer::~StreamBuffer()
|
||||||
|
{
|
||||||
unloadVolatile();
|
unloadVolatile();
|
||||||
}
|
}
|
||||||
|
|
||||||
love::graphics::StreamBuffer::MapInfo StreamBuffer::map(size_t minsize) {
|
ptrdiff_t StreamBuffer::getHandle() const
|
||||||
|
{
|
||||||
|
return (ptrdiff_t) buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
love::graphics::StreamBuffer::MapInfo StreamBuffer::map(size_t minsize)
|
||||||
|
{
|
||||||
(void)minsize;
|
(void)minsize;
|
||||||
return love::graphics::StreamBuffer::MapInfo((uint8*) allocInfo.pMappedData + usedGPUMemory, getSize());
|
return love::graphics::StreamBuffer::MapInfo((uint8*) allocInfo.pMappedData + usedGPUMemory, getSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t StreamBuffer::unmap(size_t usedSize) {
|
size_t StreamBuffer::unmap(size_t usedSize)
|
||||||
|
{
|
||||||
return usedGPUMemory;
|
return usedGPUMemory;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamBuffer::markUsed(size_t usedSize) {
|
void StreamBuffer::markUsed(size_t usedSize)
|
||||||
|
{
|
||||||
usedGPUMemory += usedSize;
|
usedGPUMemory += usedSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamBuffer::nextFrame() {
|
void StreamBuffer::nextFrame()
|
||||||
|
{
|
||||||
usedGPUMemory = 0;
|
usedGPUMemory = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // vulkan
|
} // vulkan
|
||||||
} // graphics
|
} // graphics
|
||||||
} // love
|
} // love
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef LOVE_GRAPHICS_VULKAN_STREAMBUFFER_H
|
#pragma once
|
||||||
#define LOVE_GRAPHICS_VULKAN_STREAMBUFFER_H
|
|
||||||
|
|
||||||
#include "graphics/Volatile.h"
|
#include "graphics/Volatile.h"
|
||||||
#include "modules/graphics/StreamBuffer.h"
|
#include "modules/graphics/StreamBuffer.h"
|
||||||
@@ -7,12 +6,21 @@
|
|||||||
|
|
||||||
#include "VulkanWrapper.h"
|
#include "VulkanWrapper.h"
|
||||||
|
|
||||||
namespace love {
|
namespace love
|
||||||
namespace graphics {
|
{
|
||||||
namespace vulkan {
|
namespace graphics
|
||||||
class StreamBuffer : public love::graphics::StreamBuffer, public graphics::Volatile {
|
{
|
||||||
|
namespace vulkan
|
||||||
|
{
|
||||||
|
|
||||||
|
class Graphics;
|
||||||
|
|
||||||
|
class StreamBuffer
|
||||||
|
: public love::graphics::StreamBuffer
|
||||||
|
, public graphics::Volatile
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
StreamBuffer(graphics::Graphics* gfx, BufferUsage mode, size_t size);
|
StreamBuffer(graphics::Graphics *gfx, BufferUsage mode, size_t size);
|
||||||
virtual ~StreamBuffer();
|
virtual ~StreamBuffer();
|
||||||
|
|
||||||
virtual bool loadVolatile() override;
|
virtual bool loadVolatile() override;
|
||||||
@@ -25,12 +33,10 @@ public:
|
|||||||
|
|
||||||
void nextFrame() override;
|
void nextFrame() override;
|
||||||
|
|
||||||
ptrdiff_t getHandle() const override {
|
ptrdiff_t getHandle() const override;
|
||||||
return (ptrdiff_t) buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
graphics::Graphics* gfx;
|
Graphics *vgfx = nullptr;
|
||||||
VmaAllocator allocator;
|
VmaAllocator allocator;
|
||||||
VmaAllocation allocation;
|
VmaAllocation allocation;
|
||||||
VmaAllocationInfo allocInfo;
|
VmaAllocationInfo allocInfo;
|
||||||
@@ -38,8 +44,7 @@ private:
|
|||||||
size_t usedGPUMemory;
|
size_t usedGPUMemory;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // vulkan
|
} // vulkan
|
||||||
} // graphics
|
} // graphics
|
||||||
} // love
|
} // love
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -4,22 +4,26 @@
|
|||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
// make vulkan::Graphics functions available
|
namespace love
|
||||||
#define vgfx ((Graphics*)gfx)
|
{
|
||||||
|
namespace graphics
|
||||||
|
{
|
||||||
|
namespace vulkan
|
||||||
|
{
|
||||||
|
|
||||||
namespace love {
|
Texture::Texture(love::graphics::Graphics *gfx, const Settings &settings, const Slices *data)
|
||||||
namespace graphics {
|
: love::graphics::Texture(gfx, settings, data)
|
||||||
namespace vulkan {
|
, vgfx(dynamic_cast<Graphics*>(gfx))
|
||||||
Texture::Texture(love::graphics::Graphics* gfx, const Settings& settings, const Slices* data)
|
, slices(settings.type)
|
||||||
: love::graphics::Texture(gfx, settings, data), gfx(gfx), slices(settings.type) {
|
{
|
||||||
if (data) {
|
if (data)
|
||||||
slices = *data;
|
slices = *data;
|
||||||
}
|
|
||||||
|
|
||||||
loadVolatile();
|
loadVolatile();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Texture::loadVolatile() {
|
bool Texture::loadVolatile()
|
||||||
|
{
|
||||||
allocator = vgfx->getVmaAllocator();
|
allocator = vgfx->getVmaAllocator();
|
||||||
device = vgfx->getDevice();
|
device = vgfx->getDevice();
|
||||||
|
|
||||||
@@ -44,10 +48,10 @@ bool Texture::loadVolatile() {
|
|||||||
|
|
||||||
layerCount = 1;
|
layerCount = 1;
|
||||||
|
|
||||||
if (texType == TEXTURE_2D_ARRAY) {
|
if (texType == TEXTURE_2D_ARRAY)
|
||||||
layerCount = getLayerCount();
|
layerCount = getLayerCount();
|
||||||
}
|
else if (texType == TEXTURE_CUBE)
|
||||||
else if (texType == TEXTURE_CUBE) {
|
{
|
||||||
layerCount = 6;
|
layerCount = 6;
|
||||||
createFlags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
|
createFlags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
|
||||||
}
|
}
|
||||||
@@ -70,9 +74,8 @@ bool Texture::loadVolatile() {
|
|||||||
|
|
||||||
VmaAllocationCreateInfo imageAllocationCreateInfo{};
|
VmaAllocationCreateInfo imageAllocationCreateInfo{};
|
||||||
|
|
||||||
if (vmaCreateImage(allocator, &imageInfo, &imageAllocationCreateInfo, &textureImage, &textureImageAllocation, nullptr) != VK_SUCCESS) {
|
if (vmaCreateImage(allocator, &imageInfo, &imageAllocationCreateInfo, &textureImage, &textureImageAllocation, nullptr) != VK_SUCCESS)
|
||||||
throw love::Exception("failed to create image");
|
throw love::Exception("failed to create image");
|
||||||
}
|
|
||||||
|
|
||||||
auto commandBuffer = vgfx->getDataTransferCommandBuffer();
|
auto commandBuffer = vgfx->getDataTransferCommandBuffer();
|
||||||
|
|
||||||
@@ -90,37 +93,36 @@ bool Texture::loadVolatile() {
|
|||||||
|
|
||||||
bool hasdata = slices.get(0, 0) != nullptr;
|
bool hasdata = slices.get(0, 0) != nullptr;
|
||||||
|
|
||||||
if (hasdata) {
|
if (hasdata)
|
||||||
for (int mip = 0; mip < layerCount; mip++) {
|
for (int mip = 0; mip < layerCount; mip++)
|
||||||
|
{
|
||||||
// fixme: deal with compressed images.
|
// fixme: deal with compressed images.
|
||||||
|
|
||||||
int sliceCount;
|
int sliceCount;
|
||||||
if (texType == TEXTURE_CUBE) {
|
if (texType == TEXTURE_CUBE)
|
||||||
sliceCount = 6;
|
sliceCount = 6;
|
||||||
} else {
|
else
|
||||||
sliceCount = slices.getSliceCount();
|
sliceCount = slices.getSliceCount();
|
||||||
}
|
for (int slice = 0; slice < sliceCount; slice++)
|
||||||
for (int slice = 0; slice < sliceCount; slice++) {
|
{
|
||||||
auto* id = slices.get(slice, mip);
|
auto* id = slices.get(slice, mip);
|
||||||
if (id != nullptr) {
|
if (id != nullptr)
|
||||||
uploadImageData(id, mip, slice, 0, 0);
|
uploadImageData(id, mip, slice, 0, 0);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
else
|
||||||
clear();
|
clear();
|
||||||
}
|
|
||||||
createTextureImageView();
|
createTextureImageView();
|
||||||
textureSampler = vgfx->getCachedSampler(samplerState);
|
textureSampler = vgfx->getCachedSampler(samplerState);
|
||||||
|
|
||||||
if (slices.getMipmapCount() <= 1 && getMipmapsMode() != MIPMAPS_NONE) {
|
if (slices.getMipmapCount() <= 1 && getMipmapsMode() != MIPMAPS_NONE)
|
||||||
generateMipmaps();
|
generateMipmaps();
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Texture::unloadVolatile() {
|
void Texture::unloadVolatile()
|
||||||
|
{
|
||||||
if (textureImage == VK_NULL_HANDLE)
|
if (textureImage == VK_NULL_HANDLE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -137,20 +139,44 @@ void Texture::unloadVolatile() {
|
|||||||
textureImage = VK_NULL_HANDLE;
|
textureImage = VK_NULL_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
Texture::~Texture() {
|
Texture::~Texture()
|
||||||
|
{
|
||||||
unloadVolatile();
|
unloadVolatile();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Texture::setSamplerState(const SamplerState &s) {
|
ptrdiff_t Texture::getRenderTargetHandle() const
|
||||||
|
{
|
||||||
|
return (ptrdiff_t)textureImageView;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptrdiff_t Texture::getSamplerHandle() const
|
||||||
|
{
|
||||||
|
return (ptrdiff_t)textureSampler;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Texture::getMSAA() const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptrdiff_t Texture::getHandle() const
|
||||||
|
{
|
||||||
|
return (ptrdiff_t)textureImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Texture::setSamplerState(const SamplerState &s)
|
||||||
|
{
|
||||||
love::graphics::Texture::setSamplerState(s);
|
love::graphics::Texture::setSamplerState(s);
|
||||||
textureSampler = vgfx->getCachedSampler(s);
|
textureSampler = vgfx->getCachedSampler(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
VkImageLayout Texture::getImageLayout() const {
|
VkImageLayout Texture::getImageLayout() const
|
||||||
|
{
|
||||||
return imageLayout;
|
return imageLayout;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Texture::createTextureImageView() {
|
void Texture::createTextureImageView()
|
||||||
|
{
|
||||||
auto vulkanFormat = Vulkan::getTextureFormat(format);
|
auto vulkanFormat = Vulkan::getTextureFormat(format);
|
||||||
|
|
||||||
VkImageViewCreateInfo viewInfo{};
|
VkImageViewCreateInfo viewInfo{};
|
||||||
@@ -168,12 +194,12 @@ void Texture::createTextureImageView() {
|
|||||||
viewInfo.components.b = vulkanFormat.swizzleB;
|
viewInfo.components.b = vulkanFormat.swizzleB;
|
||||||
viewInfo.components.a = vulkanFormat.swizzleA;
|
viewInfo.components.a = vulkanFormat.swizzleA;
|
||||||
|
|
||||||
if (vkCreateImageView(device, &viewInfo, nullptr, &textureImageView) != VK_SUCCESS) {
|
if (vkCreateImageView(device, &viewInfo, nullptr, &textureImageView) != VK_SUCCESS)
|
||||||
throw love::Exception("could not create texture image view");
|
throw love::Exception("could not create texture image view");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Texture::clear() {
|
void Texture::clear()
|
||||||
|
{
|
||||||
auto commandBuffer = vgfx->getDataTransferCommandBuffer();
|
auto commandBuffer = vgfx->getDataTransferCommandBuffer();
|
||||||
|
|
||||||
auto clearColor = getClearValue();
|
auto clearColor = getClearValue();
|
||||||
@@ -185,7 +211,8 @@ void Texture::clear() {
|
|||||||
range.baseArrayLayer = 0;
|
range.baseArrayLayer = 0;
|
||||||
range.layerCount = VK_REMAINING_ARRAY_LAYERS;
|
range.layerCount = VK_REMAINING_ARRAY_LAYERS;
|
||||||
|
|
||||||
if (imageLayout != VK_IMAGE_LAYOUT_GENERAL) {
|
if (imageLayout != VK_IMAGE_LAYOUT_GENERAL)
|
||||||
|
{
|
||||||
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage,
|
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage,
|
||||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
0, range.levelCount, 0, range.layerCount);
|
0, range.levelCount, 0, range.layerCount);
|
||||||
@@ -196,16 +223,17 @@ void Texture::clear() {
|
|||||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||||
0, range.levelCount, 0, range.layerCount);
|
0, range.levelCount, 0, range.layerCount);
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
vkCmdClearColorImage(commandBuffer, textureImage, VK_IMAGE_LAYOUT_GENERAL, &clearColor, 1, &range);
|
vkCmdClearColorImage(commandBuffer, textureImage, VK_IMAGE_LAYOUT_GENERAL, &clearColor, 1, &range);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VkClearColorValue Texture::getClearValue() {
|
VkClearColorValue Texture::getClearValue()
|
||||||
|
{
|
||||||
auto vulkanFormat = Vulkan::getTextureFormat(format);
|
auto vulkanFormat = Vulkan::getTextureFormat(format);
|
||||||
|
|
||||||
VkClearColorValue clearColor{};
|
VkClearColorValue clearColor{};
|
||||||
switch (vulkanFormat.internalFormatRepresentation) {
|
switch (vulkanFormat.internalFormatRepresentation)
|
||||||
|
{
|
||||||
case FORMATREPRESENTATION_FLOAT:
|
case FORMATREPRESENTATION_FLOAT:
|
||||||
clearColor.float32[0] = 0.0f;
|
clearColor.float32[0] = 0.0f;
|
||||||
clearColor.float32[1] = 0.0f;
|
clearColor.float32[1] = 0.0f;
|
||||||
@@ -228,7 +256,8 @@ VkClearColorValue Texture::getClearValue() {
|
|||||||
return clearColor;
|
return clearColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Texture::generateMipmapsInternal() {
|
void Texture::generateMipmapsInternal()
|
||||||
|
{
|
||||||
auto commandBuffer = vgfx->getDataTransferCommandBuffer();
|
auto commandBuffer = vgfx->getDataTransferCommandBuffer();
|
||||||
|
|
||||||
if (imageLayout != VK_IMAGE_LAYOUT_GENERAL)
|
if (imageLayout != VK_IMAGE_LAYOUT_GENERAL)
|
||||||
@@ -249,7 +278,8 @@ void Texture::generateMipmapsInternal() {
|
|||||||
|
|
||||||
uint32_t mipLevels = static_cast<uint32_t>(getMipmapCount());
|
uint32_t mipLevels = static_cast<uint32_t>(getMipmapCount());
|
||||||
|
|
||||||
for (uint32_t i = 1; i < mipLevels; i++) {
|
for (uint32_t i = 1; i < mipLevels; i++)
|
||||||
|
{
|
||||||
barrier.subresourceRange.baseMipLevel = i - 1;
|
barrier.subresourceRange.baseMipLevel = i - 1;
|
||||||
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||||
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||||
@@ -309,7 +339,8 @@ void Texture::generateMipmapsInternal() {
|
|||||||
1, &barrier);
|
1, &barrier);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Texture::uploadByteData(PixelFormat pixelformat, const void* data, size_t size, int level, int slice, const Rect& r) {
|
void Texture::uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r)
|
||||||
|
{
|
||||||
VkBuffer stagingBuffer;
|
VkBuffer stagingBuffer;
|
||||||
VmaAllocation vmaAllocation;
|
VmaAllocation vmaAllocation;
|
||||||
|
|
||||||
@@ -346,7 +377,8 @@ void Texture::uploadByteData(PixelFormat pixelformat, const void* data, size_t s
|
|||||||
auto commandBuffer = vgfx->getDataTransferCommandBuffer();
|
auto commandBuffer = vgfx->getDataTransferCommandBuffer();
|
||||||
|
|
||||||
|
|
||||||
if (imageLayout != VK_IMAGE_LAYOUT_GENERAL) {
|
if (imageLayout != VK_IMAGE_LAYOUT_GENERAL)
|
||||||
|
{
|
||||||
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage,
|
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage,
|
||||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
level, 1, slice, 1);
|
level, 1, slice, 1);
|
||||||
@@ -365,7 +397,7 @@ void Texture::uploadByteData(PixelFormat pixelformat, const void* data, size_t s
|
|||||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||||
level, 1, slice, 1);
|
level, 1, slice, 1);
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
vkCmdCopyBufferToImage(
|
vkCmdCopyBufferToImage(
|
||||||
commandBuffer,
|
commandBuffer,
|
||||||
stagingBuffer,
|
stagingBuffer,
|
||||||
@@ -374,14 +406,14 @@ void Texture::uploadByteData(PixelFormat pixelformat, const void* data, size_t s
|
|||||||
1,
|
1,
|
||||||
®ion
|
®ion
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
vgfx->queueCleanUp([allocator = allocator, stagingBuffer, vmaAllocation]() {
|
vgfx->queueCleanUp([allocator = allocator, stagingBuffer, vmaAllocation]() {
|
||||||
vmaDestroyBuffer(allocator, stagingBuffer, vmaAllocation);
|
vmaDestroyBuffer(allocator, stagingBuffer, vmaAllocation);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Texture::copyFromBuffer(graphics::Buffer* source, size_t sourceoffset, int sourcewidth, size_t size, int slice, int mipmap, const Rect& rect) {
|
void Texture::copyFromBuffer(graphics::Buffer *source, size_t sourceoffset, int sourcewidth, size_t size, int slice, int mipmap, const Rect &rect)
|
||||||
|
{
|
||||||
auto commandBuffer = vgfx->getDataTransferCommandBuffer();
|
auto commandBuffer = vgfx->getDataTransferCommandBuffer();
|
||||||
|
|
||||||
VkImageSubresourceLayers layers{};
|
VkImageSubresourceLayers layers{};
|
||||||
@@ -398,7 +430,8 @@ void Texture::copyFromBuffer(graphics::Buffer* source, size_t sourceoffset, int
|
|||||||
region.imageExtent.width = static_cast<uint32_t>(rect.w);
|
region.imageExtent.width = static_cast<uint32_t>(rect.w);
|
||||||
region.imageExtent.height = static_cast<uint32_t>(rect.h);
|
region.imageExtent.height = static_cast<uint32_t>(rect.h);
|
||||||
|
|
||||||
if (imageLayout != VK_IMAGE_LAYOUT_GENERAL) {
|
if (imageLayout != VK_IMAGE_LAYOUT_GENERAL)
|
||||||
|
{
|
||||||
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||||
|
|
||||||
vkCmdCopyBufferToImage(commandBuffer, (VkBuffer)source->getHandle(), textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
vkCmdCopyBufferToImage(commandBuffer, (VkBuffer)source->getHandle(), textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
||||||
@@ -409,7 +442,8 @@ void Texture::copyFromBuffer(graphics::Buffer* source, size_t sourceoffset, int
|
|||||||
vkCmdCopyBufferToImage(commandBuffer, (VkBuffer)source->getHandle(), textureImage, VK_IMAGE_LAYOUT_GENERAL, 1, ®ion);
|
vkCmdCopyBufferToImage(commandBuffer, (VkBuffer)source->getHandle(), textureImage, VK_IMAGE_LAYOUT_GENERAL, 1, ®ion);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Texture::copyToBuffer(graphics::Buffer* dest, int slice, int mipmap, const Rect& rect, size_t destoffset, int destwidth, size_t size) {
|
void Texture::copyToBuffer(graphics::Buffer *dest, int slice, int mipmap, const Rect &rect, size_t destoffset, int destwidth, size_t size)
|
||||||
|
{
|
||||||
auto commandBuffer = vgfx->getReadbackCommandBuffer();
|
auto commandBuffer = vgfx->getReadbackCommandBuffer();
|
||||||
|
|
||||||
VkImageSubresourceLayers layers{};
|
VkImageSubresourceLayers layers{};
|
||||||
@@ -427,7 +461,8 @@ void Texture::copyToBuffer(graphics::Buffer* dest, int slice, int mipmap, const
|
|||||||
region.imageExtent.height = static_cast<uint32_t>(rect.h);
|
region.imageExtent.height = static_cast<uint32_t>(rect.h);
|
||||||
region.imageExtent.depth = 1;
|
region.imageExtent.depth = 1;
|
||||||
|
|
||||||
if (imageLayout != VK_IMAGE_LAYOUT_GENERAL) {
|
if (imageLayout != VK_IMAGE_LAYOUT_GENERAL)
|
||||||
|
{
|
||||||
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||||
|
|
||||||
vkCmdCopyImageToBuffer(commandBuffer, textureImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, (VkBuffer) dest->getHandle(), 1, ®ion);
|
vkCmdCopyImageToBuffer(commandBuffer, textureImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, (VkBuffer) dest->getHandle(), 1, ®ion);
|
||||||
|
|||||||
@@ -1,20 +1,26 @@
|
|||||||
#ifndef LOVE_GRAPHICS_VULKAN_TEXTURE_H
|
#pragma once
|
||||||
#define LOVE_GRAPHICS_VULKAN_TEXTURE_H
|
|
||||||
|
|
||||||
#include "graphics/Texture.h"
|
#include "graphics/Texture.h"
|
||||||
#include "graphics/Volatile.h"
|
#include "graphics/Volatile.h"
|
||||||
|
|
||||||
#include "VulkanWrapper.h"
|
#include "VulkanWrapper.h"
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
|
namespace love
|
||||||
|
{
|
||||||
|
namespace graphics
|
||||||
|
{
|
||||||
|
namespace vulkan
|
||||||
|
{
|
||||||
|
|
||||||
namespace love {
|
class Graphics;
|
||||||
namespace graphics {
|
|
||||||
namespace vulkan {
|
class Texture
|
||||||
class Texture : public graphics::Texture, public Volatile {
|
: public graphics::Texture
|
||||||
|
, public Volatile
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
Texture(love::graphics::Graphics* gfx, const Settings& settings, const Slices* data);
|
Texture(love::graphics::Graphics *gfx, const Settings &settings, const Slices *data);
|
||||||
~Texture();
|
~Texture();
|
||||||
|
|
||||||
virtual bool loadVolatile() override;
|
virtual bool loadVolatile() override;
|
||||||
@@ -24,18 +30,18 @@ public:
|
|||||||
|
|
||||||
VkImageLayout getImageLayout() const;
|
VkImageLayout getImageLayout() const;
|
||||||
|
|
||||||
void copyFromBuffer(graphics::Buffer* source, size_t sourceoffset, int sourcewidth, size_t size, int slice, int mipmap, const Rect& rect) override;
|
void copyFromBuffer(graphics::Buffer *source, size_t sourceoffset, int sourcewidth, size_t size, int slice, int mipmap, const Rect &rect) override;
|
||||||
void copyToBuffer(graphics::Buffer* dest, int slice, int mipmap, const Rect& rect, size_t destoffset, int destwidth, size_t size) override;
|
void copyToBuffer(graphics::Buffer *dest, int slice, int mipmap, const Rect &rect, size_t destoffset, int destwidth, size_t size) override;
|
||||||
|
|
||||||
ptrdiff_t getRenderTargetHandle() const override { return (ptrdiff_t)textureImageView; };
|
ptrdiff_t getRenderTargetHandle() const override;
|
||||||
ptrdiff_t getSamplerHandle() const override { return (ptrdiff_t)textureSampler; };
|
ptrdiff_t getSamplerHandle() const override;
|
||||||
|
|
||||||
void uploadByteData(PixelFormat pixelformat, const void* data, size_t size, int level, int slice, const Rect& r) override;
|
void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r) override;
|
||||||
|
|
||||||
void generateMipmapsInternal() override;
|
void generateMipmapsInternal() override;
|
||||||
|
|
||||||
int getMSAA() const override { return 0; };
|
int getMSAA() const override;
|
||||||
ptrdiff_t getHandle() const override { return (ptrdiff_t)textureImage; }
|
ptrdiff_t getHandle() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void createTextureImageView();
|
void createTextureImageView();
|
||||||
@@ -43,7 +49,7 @@ private:
|
|||||||
|
|
||||||
VkClearColorValue getClearValue();
|
VkClearColorValue getClearValue();
|
||||||
|
|
||||||
graphics::Graphics* gfx = nullptr;
|
Graphics *vgfx = nullptr;
|
||||||
VkDevice device = VK_NULL_HANDLE;
|
VkDevice device = VK_NULL_HANDLE;
|
||||||
VmaAllocator allocator = VK_NULL_HANDLE;
|
VmaAllocator allocator = VK_NULL_HANDLE;
|
||||||
VkImage textureImage = VK_NULL_HANDLE;
|
VkImage textureImage = VK_NULL_HANDLE;
|
||||||
@@ -54,8 +60,7 @@ private:
|
|||||||
Slices slices;
|
Slices slices;
|
||||||
int layerCount = 0;
|
int layerCount = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // vulkan
|
} // vulkan
|
||||||
} // graphics
|
} // graphics
|
||||||
} // love
|
} // love
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -3,34 +3,45 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
|
||||||
namespace love {
|
namespace love
|
||||||
namespace graphics {
|
{
|
||||||
namespace vulkan {
|
namespace graphics
|
||||||
|
{
|
||||||
|
namespace vulkan
|
||||||
|
{
|
||||||
|
|
||||||
static uint32_t numShaderSwitches;
|
static uint32_t numShaderSwitches;
|
||||||
static int vsync = 1;
|
static int vsync = 1;
|
||||||
|
|
||||||
void Vulkan::shaderSwitch() {
|
void Vulkan::shaderSwitch()
|
||||||
|
{
|
||||||
numShaderSwitches++;
|
numShaderSwitches++;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Vulkan::getNumShaderSwitches() {
|
uint32_t Vulkan::getNumShaderSwitches()
|
||||||
|
{
|
||||||
return numShaderSwitches;
|
return numShaderSwitches;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Vulkan::resetShaderSwitches() {
|
void Vulkan::resetShaderSwitches()
|
||||||
|
{
|
||||||
numShaderSwitches = 0;
|
numShaderSwitches = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Vulkan::setVsync(int value) {
|
void Vulkan::setVsync(int value)
|
||||||
|
{
|
||||||
vsync = value;
|
vsync = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Vulkan::getVsync() {
|
int Vulkan::getVsync()
|
||||||
|
{
|
||||||
return vsync;
|
return vsync;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkFormat Vulkan::getVulkanVertexFormat(DataFormat format) {
|
VkFormat Vulkan::getVulkanVertexFormat(DataFormat format)
|
||||||
switch (format) {
|
{
|
||||||
|
switch (format)
|
||||||
|
{
|
||||||
case DATAFORMAT_FLOAT:
|
case DATAFORMAT_FLOAT:
|
||||||
return VK_FORMAT_R32_SFLOAT;
|
return VK_FORMAT_R32_SFLOAT;
|
||||||
case DATAFORMAT_FLOAT_VEC2:
|
case DATAFORMAT_FLOAT_VEC2:
|
||||||
@@ -110,10 +121,12 @@ VkFormat Vulkan::getVulkanVertexFormat(DataFormat format) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureFormat Vulkan::getTextureFormat(PixelFormat format) {
|
TextureFormat Vulkan::getTextureFormat(PixelFormat format)
|
||||||
|
{
|
||||||
TextureFormat textureFormat{};
|
TextureFormat textureFormat{};
|
||||||
|
|
||||||
switch (format) {
|
switch (format)
|
||||||
|
{
|
||||||
case PIXELFORMAT_UNKNOWN:
|
case PIXELFORMAT_UNKNOWN:
|
||||||
throw love::Exception("unknown pixel format");
|
throw love::Exception("unknown pixel format");
|
||||||
case PIXELFORMAT_NORMAL:
|
case PIXELFORMAT_NORMAL:
|
||||||
@@ -353,8 +366,10 @@ TextureFormat Vulkan::getTextureFormat(PixelFormat format) {
|
|||||||
|
|
||||||
// values taken from https://pcisig.com/membership/member-companies
|
// values taken from https://pcisig.com/membership/member-companies
|
||||||
// as specified at https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceProperties.html
|
// as specified at https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceProperties.html
|
||||||
std::string Vulkan::getVendorName(uint32_t vendorId) {
|
std::string Vulkan::getVendorName(uint32_t vendorId)
|
||||||
switch (vendorId) {
|
{
|
||||||
|
switch (vendorId)
|
||||||
|
{
|
||||||
case 4130:
|
case 4130:
|
||||||
return "AMD";
|
return "AMD";
|
||||||
case 4318:
|
case 4318:
|
||||||
@@ -376,7 +391,8 @@ std::string Vulkan::getVendorName(uint32_t vendorId) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Vulkan::getVulkanApiVersion(uint32_t version) {
|
std::string Vulkan::getVulkanApiVersion(uint32_t version)
|
||||||
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
ss << VK_API_VERSION_MAJOR(version)
|
ss << VK_API_VERSION_MAJOR(version)
|
||||||
@@ -386,8 +402,10 @@ std::string Vulkan::getVulkanApiVersion(uint32_t version) {
|
|||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
VkPrimitiveTopology Vulkan::getPrimitiveTypeTopology(graphics::PrimitiveType primitiveType) {
|
VkPrimitiveTopology Vulkan::getPrimitiveTypeTopology(graphics::PrimitiveType primitiveType)
|
||||||
switch (primitiveType) {
|
{
|
||||||
|
switch (primitiveType)
|
||||||
|
{
|
||||||
case PRIMITIVE_POINTS:
|
case PRIMITIVE_POINTS:
|
||||||
return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
|
return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
|
||||||
case PRIMITIVE_TRIANGLES:
|
case PRIMITIVE_TRIANGLES:
|
||||||
@@ -401,8 +419,10 @@ VkPrimitiveTopology Vulkan::getPrimitiveTypeTopology(graphics::PrimitiveType pri
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VkBlendFactor Vulkan::getBlendFactor(BlendFactor blendFactor) {
|
VkBlendFactor Vulkan::getBlendFactor(BlendFactor blendFactor)
|
||||||
switch (blendFactor) {
|
{
|
||||||
|
switch (blendFactor)
|
||||||
|
{
|
||||||
case BLENDFACTOR_ZERO:
|
case BLENDFACTOR_ZERO:
|
||||||
return VK_BLEND_FACTOR_ZERO;
|
return VK_BLEND_FACTOR_ZERO;
|
||||||
case BLENDFACTOR_ONE:
|
case BLENDFACTOR_ONE:
|
||||||
@@ -430,8 +450,10 @@ VkBlendFactor Vulkan::getBlendFactor(BlendFactor blendFactor) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VkBlendOp Vulkan::getBlendOp(BlendOperation op) {
|
VkBlendOp Vulkan::getBlendOp(BlendOperation op)
|
||||||
switch (op) {
|
{
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
case BLENDOP_ADD:
|
case BLENDOP_ADD:
|
||||||
return VK_BLEND_OP_ADD;
|
return VK_BLEND_OP_ADD;
|
||||||
case BLENDOP_MAX:
|
case BLENDOP_MAX:
|
||||||
@@ -447,35 +469,34 @@ VkBlendOp Vulkan::getBlendOp(BlendOperation op) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VkBool32 Vulkan::getBool(bool b) {
|
VkBool32 Vulkan::getBool(bool b)
|
||||||
if (b) {
|
{
|
||||||
|
if (b)
|
||||||
return VK_TRUE;
|
return VK_TRUE;
|
||||||
} else {
|
else
|
||||||
return VK_FALSE;
|
return VK_FALSE;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VkColorComponentFlags Vulkan::getColorMask(ColorChannelMask mask) {
|
VkColorComponentFlags Vulkan::getColorMask(ColorChannelMask mask)
|
||||||
|
{
|
||||||
VkColorComponentFlags flags = 0;
|
VkColorComponentFlags flags = 0;
|
||||||
|
|
||||||
if (mask.r) {
|
if (mask.r)
|
||||||
flags |= VK_COLOR_COMPONENT_R_BIT;
|
flags |= VK_COLOR_COMPONENT_R_BIT;
|
||||||
}
|
if (mask.g)
|
||||||
if (mask.g) {
|
|
||||||
flags |= VK_COLOR_COMPONENT_G_BIT;
|
flags |= VK_COLOR_COMPONENT_G_BIT;
|
||||||
}
|
if (mask.b)
|
||||||
if (mask.b) {
|
|
||||||
flags |= VK_COLOR_COMPONENT_B_BIT;
|
flags |= VK_COLOR_COMPONENT_B_BIT;
|
||||||
}
|
if (mask.a)
|
||||||
if (mask.a) {
|
|
||||||
flags |= VK_COLOR_COMPONENT_A_BIT;
|
flags |= VK_COLOR_COMPONENT_A_BIT;
|
||||||
}
|
|
||||||
|
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkFrontFace Vulkan::getFrontFace(Winding winding) {
|
VkFrontFace Vulkan::getFrontFace(Winding winding)
|
||||||
switch (winding) {
|
{
|
||||||
|
switch (winding)
|
||||||
|
{
|
||||||
case WINDING_CW:
|
case WINDING_CW:
|
||||||
return VK_FRONT_FACE_CLOCKWISE;
|
return VK_FRONT_FACE_CLOCKWISE;
|
||||||
case WINDING_CCW:
|
case WINDING_CCW:
|
||||||
@@ -485,8 +506,10 @@ VkFrontFace Vulkan::getFrontFace(Winding winding) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VkCullModeFlags Vulkan::getCullMode(CullMode cullmode) {
|
VkCullModeFlags Vulkan::getCullMode(CullMode cullmode)
|
||||||
switch (cullmode) {
|
{
|
||||||
|
switch (cullmode)
|
||||||
|
{
|
||||||
case CULL_BACK:
|
case CULL_BACK:
|
||||||
return VK_CULL_MODE_BACK_BIT;
|
return VK_CULL_MODE_BACK_BIT;
|
||||||
case CULL_FRONT:
|
case CULL_FRONT:
|
||||||
@@ -498,8 +521,10 @@ VkCullModeFlags Vulkan::getCullMode(CullMode cullmode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VkImageType Vulkan::getImageType(TextureType textureType) {
|
VkImageType Vulkan::getImageType(TextureType textureType)
|
||||||
switch (textureType) {
|
{
|
||||||
|
switch (textureType)
|
||||||
|
{
|
||||||
case TEXTURE_2D:
|
case TEXTURE_2D:
|
||||||
case TEXTURE_2D_ARRAY:
|
case TEXTURE_2D_ARRAY:
|
||||||
case TEXTURE_CUBE:
|
case TEXTURE_CUBE:
|
||||||
@@ -511,8 +536,10 @@ VkImageType Vulkan::getImageType(TextureType textureType) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VkImageViewType Vulkan::getImageViewType(TextureType textureType) {
|
VkImageViewType Vulkan::getImageViewType(TextureType textureType)
|
||||||
switch (textureType) {
|
{
|
||||||
|
switch (textureType)
|
||||||
|
{
|
||||||
case TEXTURE_2D:
|
case TEXTURE_2D:
|
||||||
return VK_IMAGE_VIEW_TYPE_2D;
|
return VK_IMAGE_VIEW_TYPE_2D;
|
||||||
case TEXTURE_2D_ARRAY:
|
case TEXTURE_2D_ARRAY:
|
||||||
@@ -526,16 +553,18 @@ VkImageViewType Vulkan::getImageViewType(TextureType textureType) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VkPolygonMode Vulkan::getPolygonMode(bool wireframe) {
|
VkPolygonMode Vulkan::getPolygonMode(bool wireframe)
|
||||||
if (wireframe) {
|
{
|
||||||
|
if (wireframe)
|
||||||
return VK_POLYGON_MODE_LINE;
|
return VK_POLYGON_MODE_LINE;
|
||||||
} else {
|
else
|
||||||
return VK_POLYGON_MODE_FILL;
|
return VK_POLYGON_MODE_FILL;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VkFilter Vulkan::getFilter(SamplerState::FilterMode mode) {
|
VkFilter Vulkan::getFilter(SamplerState::FilterMode mode)
|
||||||
switch (mode) {
|
{
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
case SamplerState::FILTER_LINEAR:
|
case SamplerState::FILTER_LINEAR:
|
||||||
return VK_FILTER_LINEAR;
|
return VK_FILTER_LINEAR;
|
||||||
case SamplerState::FILTER_NEAREST:
|
case SamplerState::FILTER_NEAREST:
|
||||||
@@ -545,8 +574,10 @@ VkFilter Vulkan::getFilter(SamplerState::FilterMode mode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VkSamplerAddressMode Vulkan::getWrapMode(SamplerState::WrapMode mode) {
|
VkSamplerAddressMode Vulkan::getWrapMode(SamplerState::WrapMode mode)
|
||||||
switch (mode) {
|
{
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
//fixme: not accounting for different clamps (how does that work in vulkan?)
|
//fixme: not accounting for different clamps (how does that work in vulkan?)
|
||||||
case SamplerState::WRAP_CLAMP:
|
case SamplerState::WRAP_CLAMP:
|
||||||
case SamplerState::WRAP_CLAMP_ZERO:
|
case SamplerState::WRAP_CLAMP_ZERO:
|
||||||
@@ -561,8 +592,10 @@ VkSamplerAddressMode Vulkan::getWrapMode(SamplerState::WrapMode mode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VkCompareOp Vulkan::getCompareOp(CompareMode mode) {
|
VkCompareOp Vulkan::getCompareOp(CompareMode mode)
|
||||||
switch (mode) {
|
{
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
case COMPARE_LESS:
|
case COMPARE_LESS:
|
||||||
return VK_COMPARE_OP_LESS;
|
return VK_COMPARE_OP_LESS;
|
||||||
case COMPARE_LEQUAL:
|
case COMPARE_LEQUAL:
|
||||||
@@ -584,8 +617,10 @@ VkCompareOp Vulkan::getCompareOp(CompareMode mode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VkSamplerMipmapMode Vulkan::getMipMapMode(SamplerState::MipmapFilterMode mode) {
|
VkSamplerMipmapMode Vulkan::getMipMapMode(SamplerState::MipmapFilterMode mode)
|
||||||
switch (mode) {
|
{
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
case SamplerState::MIPMAP_FILTER_NEAREST:
|
case SamplerState::MIPMAP_FILTER_NEAREST:
|
||||||
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||||
case SamplerState::MIPMAP_FILTER_NONE:
|
case SamplerState::MIPMAP_FILTER_NONE:
|
||||||
@@ -595,9 +630,10 @@ VkSamplerMipmapMode Vulkan::getMipMapMode(SamplerState::MipmapFilterMode mode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VkDescriptorType Vulkan::getDescriptorType(graphics::Shader::UniformType type)
|
||||||
VkDescriptorType Vulkan::getDescriptorType(graphics::Shader::UniformType type) {
|
{
|
||||||
switch (type) {
|
switch (type)
|
||||||
|
{
|
||||||
case graphics::Shader::UniformType::UNIFORM_FLOAT:
|
case graphics::Shader::UniformType::UNIFORM_FLOAT:
|
||||||
case graphics::Shader::UniformType::UNIFORM_MATRIX:
|
case graphics::Shader::UniformType::UNIFORM_MATRIX:
|
||||||
case graphics::Shader::UniformType::UNIFORM_INT:
|
case graphics::Shader::UniformType::UNIFORM_INT:
|
||||||
@@ -617,8 +653,10 @@ VkDescriptorType Vulkan::getDescriptorType(graphics::Shader::UniformType type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VkStencilOp Vulkan::getStencilOp(StencilAction action) {
|
VkStencilOp Vulkan::getStencilOp(StencilAction action)
|
||||||
switch (action) {
|
{
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
case STENCIL_KEEP:
|
case STENCIL_KEEP:
|
||||||
return VK_STENCIL_OP_KEEP;
|
return VK_STENCIL_OP_KEEP;
|
||||||
case STENCIL_ZERO:
|
case STENCIL_ZERO:
|
||||||
@@ -640,8 +678,10 @@ VkStencilOp Vulkan::getStencilOp(StencilAction action) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VkIndexType Vulkan::getVulkanIndexBufferType(IndexDataType type) {
|
VkIndexType Vulkan::getVulkanIndexBufferType(IndexDataType type)
|
||||||
switch (type) {
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
case INDEX_UINT16: return VK_INDEX_TYPE_UINT16;
|
case INDEX_UINT16: return VK_INDEX_TYPE_UINT16;
|
||||||
case INDEX_UINT32: return VK_INDEX_TYPE_UINT32;
|
case INDEX_UINT32: return VK_INDEX_TYPE_UINT32;
|
||||||
default:
|
default:
|
||||||
@@ -650,7 +690,8 @@ VkIndexType Vulkan::getVulkanIndexBufferType(IndexDataType type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout,
|
void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout,
|
||||||
uint32_t baseLevel, uint32_t levelCount, uint32_t baseLayer, uint32_t layerCount) {
|
uint32_t baseLevel, uint32_t levelCount, uint32_t baseLayer, uint32_t layerCount)
|
||||||
|
{
|
||||||
VkImageMemoryBarrier barrier{};
|
VkImageMemoryBarrier barrier{};
|
||||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||||
barrier.oldLayout = oldLayout;
|
barrier.oldLayout = oldLayout;
|
||||||
@@ -667,63 +708,72 @@ void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage ima
|
|||||||
VkPipelineStageFlags sourceStage;
|
VkPipelineStageFlags sourceStage;
|
||||||
VkPipelineStageFlags destinationStage;
|
VkPipelineStageFlags destinationStage;
|
||||||
|
|
||||||
if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
|
if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||||
|
{
|
||||||
barrier.srcAccessMask = 0;
|
barrier.srcAccessMask = 0;
|
||||||
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
|
|
||||||
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||||
destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||||
}
|
}
|
||||||
else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
|
else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||||
|
{
|
||||||
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
|
|
||||||
sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||||
destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||||
}
|
}
|
||||||
else if (oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
|
else if (oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
|
||||||
|
{
|
||||||
barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
|
|
||||||
sourceStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
sourceStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||||
destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||||
}
|
}
|
||||||
else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
|
else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||||
|
{
|
||||||
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
|
|
||||||
sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||||
destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||||
}
|
}
|
||||||
else if (oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) {
|
else if (oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
|
||||||
|
{
|
||||||
barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
|
|
||||||
sourceStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
sourceStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||||
destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||||
}
|
}
|
||||||
else if (oldLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
|
else if (oldLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||||
|
{
|
||||||
barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||||
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
|
|
||||||
sourceStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
sourceStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||||
destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||||
}
|
}
|
||||||
else if (oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
|
else if (oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
|
||||||
|
{
|
||||||
barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||||
|
|
||||||
sourceStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
sourceStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||||
destinationStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
destinationStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||||
}
|
}
|
||||||
else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
|
else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
|
||||||
|
{
|
||||||
barrier.srcAccessMask = 0;
|
barrier.srcAccessMask = 0;
|
||||||
barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||||
|
|
||||||
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||||
destinationStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
destinationStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||||
}
|
}
|
||||||
else if (oldLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) {
|
else if (oldLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR)
|
||||||
|
{
|
||||||
barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||||
barrier.dstAccessMask = 0;
|
barrier.dstAccessMask = 0;
|
||||||
|
|
||||||
@@ -731,16 +781,16 @@ void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage ima
|
|||||||
destinationStage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
destinationStage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||||
}
|
}
|
||||||
// we use general for images that are both sampled and compute write
|
// we use general for images that are both sampled and compute write
|
||||||
else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_GENERAL) {
|
else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_GENERAL)
|
||||||
|
{
|
||||||
barrier.srcAccessMask = 0;
|
barrier.srcAccessMask = 0;
|
||||||
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT;
|
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT;
|
||||||
|
|
||||||
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||||
destinationStage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT;
|
destinationStage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
throw std::invalid_argument("unsupported layout transition!");
|
throw std::invalid_argument("unsupported layout transition!");
|
||||||
}
|
|
||||||
|
|
||||||
vkCmdPipelineBarrier(
|
vkCmdPipelineBarrier(
|
||||||
commandBuffer,
|
commandBuffer,
|
||||||
|
|||||||
@@ -1,20 +1,25 @@
|
|||||||
#ifndef LOVE_GRAPHICS_VULKAN_VULKAN_H
|
#pragma once
|
||||||
#define LOVE_GRAPHICS_VULKAN_VULKAN_H
|
|
||||||
|
|
||||||
#include "graphics/Graphics.h"
|
#include "graphics/Graphics.h"
|
||||||
#include "VulkanWrapper.h"
|
#include "VulkanWrapper.h"
|
||||||
|
|
||||||
namespace love {
|
namespace love
|
||||||
namespace graphics {
|
{
|
||||||
namespace vulkan {
|
namespace graphics
|
||||||
enum InternalFormatRepresentation {
|
{
|
||||||
|
namespace vulkan
|
||||||
|
{
|
||||||
|
|
||||||
|
enum InternalFormatRepresentation
|
||||||
|
{
|
||||||
FORMATREPRESENTATION_FLOAT,
|
FORMATREPRESENTATION_FLOAT,
|
||||||
FORMATREPRESENTATION_UINT,
|
FORMATREPRESENTATION_UINT,
|
||||||
FORMATREPRESENTATION_SINT,
|
FORMATREPRESENTATION_SINT,
|
||||||
FORMATREPRESENTATION_MAX_ENUM
|
FORMATREPRESENTATION_MAX_ENUM
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TextureFormat {
|
struct TextureFormat
|
||||||
|
{
|
||||||
InternalFormatRepresentation internalFormatRepresentation;
|
InternalFormatRepresentation internalFormatRepresentation;
|
||||||
VkFormat internalFormat = VK_FORMAT_UNDEFINED;
|
VkFormat internalFormat = VK_FORMAT_UNDEFINED;
|
||||||
|
|
||||||
@@ -24,7 +29,8 @@ struct TextureFormat {
|
|||||||
VkComponentSwizzle swizzleA = VK_COMPONENT_SWIZZLE_IDENTITY;
|
VkComponentSwizzle swizzleA = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Vulkan {
|
class Vulkan
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
static void shaderSwitch();
|
static void shaderSwitch();
|
||||||
static uint32_t getNumShaderSwitches();
|
static uint32_t getNumShaderSwitches();
|
||||||
@@ -59,8 +65,7 @@ public:
|
|||||||
VkCommandBuffer, VkImage, VkImageLayout oldLayout, VkImageLayout newLayout,
|
VkCommandBuffer, VkImage, VkImageLayout oldLayout, VkImageLayout newLayout,
|
||||||
uint32_t baseLevel = 0, uint32_t levelCount = 1, uint32_t baseLayer = 0, uint32_t layerCount = 1);
|
uint32_t baseLevel = 0, uint32_t levelCount = 1, uint32_t baseLayer = 0, uint32_t layerCount = 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // vulkan
|
} // vulkan
|
||||||
} // graphics
|
} // graphics
|
||||||
} // love
|
} // love
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef LOVE_GRAPHICS_VULKAN_VULKANWRAPPER_H
|
#pragma once
|
||||||
#define LOVE_GRAPHICS_VULKAN_VULKANWRAPPER_H
|
|
||||||
|
|
||||||
#include "common/config.h"
|
#include "common/config.h"
|
||||||
|
|
||||||
@@ -13,5 +12,3 @@
|
|||||||
#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1
|
#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1
|
||||||
#endif
|
#endif
|
||||||
#include "vk_mem_alloc.h"
|
#include "vk_mem_alloc.h"
|
||||||
|
|
||||||
#endif //LOVE_GRAPHICS_VULKAN_VULKANWRAPPER_H
|
|
||||||
|
|||||||
Reference in New Issue
Block a user