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