vulkan: fix canvas rendering on android

This commit is contained in:
niki
2022-08-27 20:58:17 +02:00
parent 7a67983b3d
commit 18221beb25
3 changed files with 123 additions and 83 deletions
+4 -6
View File
@@ -56,10 +56,8 @@ static const char global_syntax[] = R"(
#endif
#if __VERSION__ >= 300
#define LOVE_IO_LOCATION(x) layout (location = x)
#define LOVE_IO_BINDING(x) layout (binding = x)
#else
#define LOVE_IO_LOCATION(x)
#define LOVE_IO_BINDING(x)
#endif
#define number float
#define Image sampler2D
@@ -311,9 +309,9 @@ static const char pixel_header[] = R"(
)";
static const char pixel_functions[] = R"(
LOVE_IO_BINDING(2) uniform sampler2D love_VideoYChannel;
LOVE_IO_BINDING(3) uniform sampler2D love_VideoCbChannel;
LOVE_IO_BINDING(4) uniform sampler2D love_VideoCrChannel;
uniform sampler2D love_VideoYChannel;
uniform sampler2D love_VideoCbChannel;
uniform sampler2D love_VideoCrChannel;
vec4 VideoTexel(vec2 texcoords) {
vec3 yuv;
@@ -339,7 +337,7 @@ static const char pixel_main[] = R"(
#define love_PixelColor gl_FragColor
#endif
LOVE_IO_BINDING(1) uniform sampler2D MainTex;
uniform sampler2D MainTex;
LOVE_IO_LOCATION(0) varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord;
LOVE_IO_LOCATION(1) varying mediump vec4 VaryingColor;
+104 -71
View File
@@ -325,7 +325,6 @@ void Graphics::getAPIStats(int& shaderswitches) const {
void Graphics::unSetMode() {
created = false;
auto fpn = vkDeviceWaitIdle;
vkDeviceWaitIdle(device);
Volatile::unloadAll();
cleanup();
@@ -559,12 +558,11 @@ Matrix4 Graphics::computeDeviceProjection(const Matrix4& projection, bool render
void Graphics::setRenderTargetsInternal(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture) {
endRenderPass();
if (rts.colors.empty()) {
startRenderPass(nullptr, swapChainExtent.width, swapChainExtent.height);
bool isWindow = rts.getFirstTarget().texture == nullptr;
if (isWindow) {
startDefaultRenderPass();
} else {
// fixme: multi canvas render.
auto& firstRenderTarget = rts.getFirstTarget();
startRenderPass(dynamic_cast<Texture*>(firstRenderTarget.texture), pixelw, pixelh);
startRenderPass(rts, pixelw, pixelh, hasSRGBtexture);
}
}
@@ -615,7 +613,7 @@ void Graphics::startRecordingGraphicsCommands() {
Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), swapChainImages[imageIndex], VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
startRenderPass(nullptr, swapChainExtent.width, swapChainExtent.height);
startDefaultRenderPass();
Vulkan::resetShaderSwitches();
}
@@ -1166,7 +1164,7 @@ VkPresentModeKHR Graphics::chooseSwapPresentMode(const std::vector<VkPresentMode
return VK_PRESENT_MODE_MAILBOX_KHR;
}
else {
auto it = std::find(availablePresentModes.begin(), availablePresentModes.end(), VK_PRESENT_MODE_IMMEDIATE_KHR);
it = std::find(availablePresentModes.begin(), availablePresentModes.end(), VK_PRESENT_MODE_IMMEDIATE_KHR);
if (it != availablePresentModes.end()) {
return VK_PRESENT_MODE_IMMEDIATE_KHR;
}
@@ -1244,7 +1242,10 @@ void Graphics::createImageViews() {
void Graphics::createDefaultRenderPass() {
RenderPassConfiguration renderPassConfiguration{};
renderPassConfiguration.frameBufferFormat = swapChainImageFormat;
renderPassConfiguration.colorFormat = swapChainImageFormat;
renderPassConfiguration.msaaSamples = msaaSamples;
renderPassConfiguration.depthFormat = findDepthFormat();
renderPassConfiguration.resolve = true;
defaultRenderPass = createRenderPass(renderPassConfiguration);
}
@@ -1256,18 +1257,26 @@ void Graphics::createDefaultFramebuffers() {
configuration.renderPass = defaultRenderPass;
configuration.width = swapChainExtent.width;
configuration.height = swapChainExtent.height;
configuration.imageView = view;
configuration.imageView = colorImageView;
configuration.depthView = depthImageView;
configuration.resolveView = view;
defaultFramebuffers.push_back(createFramebuffer(configuration));
}
}
VkFramebuffer Graphics::createFramebuffer(FramebufferConfiguration configuration) {
std::array<VkImageView, 3> attachments = {
colorImageView,
depthImageView,
std::vector<VkImageView> attachments = {
configuration.imageView,
};
if (configuration.depthView) {
attachments.push_back(configuration.depthView);
}
if (configuration.resolveView) {
attachments.push_back(configuration.resolveView);
}
VkFramebufferCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
createInfo.renderPass = configuration.renderPass;
@@ -1310,35 +1319,44 @@ void Graphics::createDefaultShaders() {
}
VkRenderPass Graphics::createRenderPass(RenderPassConfiguration configuration) {
std::vector<VkAttachmentDescription> attachments;
VkAttachmentDescription colorDescription{};
colorDescription.format = swapChainImageFormat;
colorDescription.samples = msaaSamples;
colorDescription.format = configuration.colorFormat;
colorDescription.samples = configuration.msaaSamples;
colorDescription.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorDescription.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorDescription.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorDescription.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
colorDescription.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachments.push_back(colorDescription);
VkAttachmentDescription depthStencilAttachment{};
depthStencilAttachment.format = findDepthFormat();
depthStencilAttachment.samples = msaaSamples;
depthStencilAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
depthStencilAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
depthStencilAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
depthStencilAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
depthStencilAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
if (configuration.depthFormat != VK_FORMAT_UNDEFINED) {
VkAttachmentDescription depthStencilAttachment{};
depthStencilAttachment.format = configuration.depthFormat;
depthStencilAttachment.samples = configuration.msaaSamples;
depthStencilAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
depthStencilAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
depthStencilAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
depthStencilAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
depthStencilAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
attachments.push_back(depthStencilAttachment);
}
VkAttachmentDescription colorAttachmentResolve{};
colorAttachmentResolve.format = configuration.frameBufferFormat;
colorAttachmentResolve.samples = VK_SAMPLE_COUNT_1_BIT;
colorAttachmentResolve.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachmentResolve.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorAttachmentResolve.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachmentResolve.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorAttachmentResolve.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
colorAttachmentResolve.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
if (configuration.resolve) {
VkAttachmentDescription colorAttachmentResolve{};
colorAttachmentResolve.format = configuration.colorFormat;
colorAttachmentResolve.samples = VK_SAMPLE_COUNT_1_BIT;
colorAttachmentResolve.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachmentResolve.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorAttachmentResolve.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachmentResolve.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorAttachmentResolve.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
colorAttachmentResolve.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachments.push_back(colorAttachmentResolve);
}
VkAttachmentReference colorAttachmentRef{};
colorAttachmentRef.attachment = 0;
@@ -1356,10 +1374,14 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration configuration) {
subPass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subPass.colorAttachmentCount = 1;
subPass.pColorAttachments = &colorAttachmentRef;
subPass.pDepthStencilAttachment = &depthStencilAttachmentRef;
subPass.pResolveAttachments = &colorAttachmentResolveRef;
std::array<VkAttachmentDescription, 3> attachments = { colorDescription, depthStencilAttachment, colorAttachmentResolve };
if (configuration.depthFormat != VK_FORMAT_UNDEFINED) {
subPass.pDepthStencilAttachment = &depthStencilAttachmentRef;
}
if (configuration.resolve) {
subPass.pResolveAttachments = &colorAttachmentResolveRef;
}
VkSubpassDependency dependency{};
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
@@ -1475,6 +1497,8 @@ void Graphics::prepareDraw(const VertexAttributes& attributes, const BufferBindi
configuration.cullmode = cullmode;
configuration.viewportWidth = currentViewportWidth;
configuration.viewportHeight = currentViewportHeight;
configuration.msaaSamples = currentMsaaSamples;
std::vector<VkBuffer> bufferVector;
std::vector<VkDeviceSize> offsets;
@@ -1505,54 +1529,63 @@ void Graphics::prepareDraw(const VertexAttributes& attributes, const BufferBindi
vkCmdBindVertexBuffers(commandBuffers.at(currentFrame), 0, static_cast<uint32_t>(bufferVector.size()), bufferVector.data(), offsets.data());
}
void Graphics::startRenderPass(Texture* texture, uint32_t w, uint32_t h) {
void Graphics::startDefaultRenderPass() {
VkRenderPassBeginInfo renderPassInfo{};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassInfo.renderPass = defaultRenderPass;
renderPassInfo.framebuffer = defaultFramebuffers[imageIndex];
renderPassInfo.renderArea.offset = { 0, 0 };
renderPassInfo.renderArea.extent = swapChainExtent;
vkCmdBeginRenderPass(commandBuffers.at(currentFrame), &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
currentRenderPass = defaultRenderPass;
currentGraphicsPipeline = VK_NULL_HANDLE;
renderTargetTexture = VK_NULL_HANDLE;
currentViewportWidth = (float)swapChainExtent.width;
currentViewportHeight = (float)swapChainExtent.height;
currentMsaaSamples = msaaSamples;
}
void Graphics::startRenderPass(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture) {
renderTargetTexture = dynamic_cast<Texture*>(rts.colors[0].texture);
RenderPassConfiguration renderPassConfiguration{};
renderPassConfiguration.colorFormat = Vulkan::getTextureFormat(renderTargetTexture->getPixelFormat()).internalFormat;
VkRenderPass renderPass;
VkFramebuffer framebuffer;
if (texture == nullptr) {
renderTargetTexture = nullptr;
renderPass = defaultRenderPass;
framebuffer = defaultFramebuffers[imageIndex];
auto it = renderPasses.find(renderPassConfiguration);
if (it != renderPasses.end()) {
renderPass = it->second;
} else {
RenderPassConfiguration renderPassConfiguration{};
renderPassConfiguration.frameBufferFormat = Vulkan::getTextureFormat(texture->getPixelFormat()).internalFormat;
renderTargetTexture = texture;
auto it = renderPasses.find(renderPassConfiguration);
if (it != renderPasses.end()) {
renderPass = it->second;
} else {
renderPass = createRenderPass(renderPassConfiguration);
renderPasses[renderPassConfiguration] = renderPass;
}
FramebufferConfiguration configuration{};
configuration.renderPass = renderPass;
configuration.imageView = (VkImageView)texture->getRenderTargetHandle();
configuration.width = w;
configuration.height = h;
framebuffer = getFramebuffer(configuration);
renderPass = createRenderPass(renderPassConfiguration);
renderPasses[renderPassConfiguration] = renderPass;
}
FramebufferConfiguration configuration{};
configuration.renderPass = renderPass;
configuration.imageView = (VkImageView)renderTargetTexture->getRenderTargetHandle();
configuration.width = static_cast<uint32_t>(renderTargetTexture->getWidth());
configuration.height = static_cast<uint32_t>(renderTargetTexture->getHeight());
VkFramebuffer framebuffer = getFramebuffer(configuration);
Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), (VkImage)renderTargetTexture->getHandle(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
VkRenderPassBeginInfo renderPassInfo{};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassInfo.renderPass = renderPass;
renderPassInfo.framebuffer = framebuffer;
renderPassInfo.renderArea.offset = {0, 0};
renderPassInfo.renderArea.extent.width = static_cast<uint32_t>(w);
renderPassInfo.renderArea.extent.height = static_cast<uint32_t>(h);
if (renderTargetTexture) {
Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), (VkImage)texture->getHandle(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
}
renderPassInfo.renderArea.extent.width = static_cast<uint32_t>(renderTargetTexture->getWidth());
renderPassInfo.renderArea.extent.height = static_cast<uint32_t>(renderTargetTexture->getHeight());
vkCmdBeginRenderPass(commandBuffers.at(currentFrame), &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
currentRenderPass = renderPass;
currentGraphicsPipeline = VK_NULL_HANDLE;
currentViewportWidth = (float)w;
currentViewportHeight = (float)h;
currentViewportWidth = (float)renderTargetTexture->getWidth();
currentViewportHeight = (float)renderTargetTexture->getHeight();
currentMsaaSamples = VK_SAMPLE_COUNT_1_BIT;
}
void Graphics::endRenderPass() {
@@ -1661,7 +1694,7 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration config
VkPipelineMultisampleStateCreateInfo multisampling{};
multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampling.sampleShadingEnable = VK_FALSE;
multisampling.rasterizationSamples = msaaSamples;
multisampling.rasterizationSamples = configuration.msaaSamples;
multisampling.minSampleShading = 1.0f; // Optional
multisampling.pSampleMask = nullptr; // Optional
multisampling.alphaToCoverageEnable = VK_FALSE; // Optional
+15 -6
View File
@@ -25,7 +25,10 @@ namespace love {
namespace graphics {
namespace vulkan {
struct RenderPassConfiguration {
VkFormat frameBufferFormat;
VkFormat colorFormat = VK_FORMAT_UNDEFINED;
VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT;
VkFormat depthFormat = VK_FORMAT_UNDEFINED;
bool resolve = false;
bool operator==(const RenderPassConfiguration& conf) const {
return memcmp(this, &conf, sizeof(RenderPassConfiguration)) == 0;
@@ -41,6 +44,8 @@ struct RenderPassConfigurationHasher {
struct FramebufferConfiguration {
VkRenderPass renderPass = VK_NULL_HANDLE;
VkImageView imageView = VK_NULL_HANDLE;
VkImageView depthView = VK_NULL_HANDLE;
VkImageView resolveView = VK_NULL_HANDLE;
uint32_t width = 0;
uint32_t height = 0;
@@ -69,6 +74,7 @@ struct GraphicsPipelineConfiguration {
float viewportHeight;
StencilState stencil;
DepthState depthState;
VkSampleCountFlagBits msaaSamples;
GraphicsPipelineConfiguration() {
memset(this, 0, sizeof(GraphicsPipelineConfiguration));
@@ -122,14 +128,16 @@ struct SwapChainSupportDetails {
class Graphics final : public love::graphics::Graphics {
public:
Graphics() {
#ifdef LOVE_ANDROID
Graphics() {
auto result = volkInitialize();
if (result != VK_SUCCESS) {
throw love::Exception("could not initialize volk");
}
#endif
}
#else
Graphics() = default;
#endif
virtual ~Graphics();
@@ -243,7 +251,8 @@ private:
std::vector<VkVertexInputBindingDescription> &bindingDescriptions,
std::vector<VkVertexInputAttributeDescription> &attributeDescriptions);
void prepareDraw(const VertexAttributes& attributes, const BufferBindings& buffers, graphics::Texture* texture, PrimitiveType, CullMode);
void startRenderPass(Texture*, uint32_t w, uint32_t h);
void startRenderPass(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture);
void startDefaultRenderPass();
void endRenderPass();
VkSampler createSampler(const SamplerState&);
@@ -271,7 +280,7 @@ private:
VkImage depthImage = VK_NULL_HANDLE;
VkImageView depthImageView = VK_NULL_HANDLE;
VmaAllocation depthImageAllocation = VK_NULL_HANDLE;
VkRenderPass defaultRenderPass;
VkRenderPass defaultRenderPass = VK_NULL_HANDLE;
std::vector<VkFramebuffer> defaultFramebuffers;
std::unordered_map<RenderPassConfiguration, VkRenderPass, RenderPassConfigurationHasher> renderPasses;
std::unordered_map<FramebufferConfiguration, VkFramebuffer, FramebufferConfigurationHasher> framebuffers;
@@ -298,10 +307,10 @@ private:
std::vector<std::vector<std::function<void()>>> cleanUpFunctions;
// render pass variables.
graphics::Texture* currentTexture = nullptr;
Texture* renderTargetTexture = nullptr;
float currentViewportWidth = 0;
float currentViewportHeight = 0;
VkSampleCountFlagBits currentMsaaSamples = VK_SAMPLE_COUNT_1_BIT;
};
} // vulkan
} // graphics