2015-10-10 16:41:19 +02:00
|
|
|
// Copyright (c) 2015- PPSSPP Project.
|
|
|
|
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, version 2.0 or later versions.
|
|
|
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
|
|
|
|
// Official git repository and contact information can be found at
|
|
|
|
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2016-01-03 18:31:03 +01:00
|
|
|
// The Descriptor Set used for the majority of PSP rendering looks like this:
|
|
|
|
//
|
|
|
|
// * binding 0: Texture/Sampler (the PSP texture)
|
2018-04-13 12:25:57 +02:00
|
|
|
// * binding 1: Secondary texture sampler for shader blending
|
|
|
|
// * binding 2: Depal palette
|
|
|
|
// * binding 3: Base Uniform Buffer (includes fragment state)
|
|
|
|
// * binding 4: Light uniform buffer
|
|
|
|
// * binding 5: Bone uniform buffer
|
|
|
|
// * binding 6: Tess data storage buffer
|
2016-01-03 18:31:03 +01:00
|
|
|
//
|
|
|
|
// All shaders conform to this layout, so they are all compatible with the same descriptor set.
|
|
|
|
// The format of the various uniform buffers may vary though - vertex shaders that don't skin
|
|
|
|
// won't get any bone data, etc.
|
2015-10-10 16:41:19 +02:00
|
|
|
|
2020-10-05 20:58:33 +02:00
|
|
|
#include "Common/Data/Collections/Hashmaps.h"
|
2021-12-09 18:39:55 -08:00
|
|
|
#include "Common/GPU/Vulkan/VulkanMemory.h"
|
2017-08-20 11:30:19 +02:00
|
|
|
|
2015-10-10 16:41:19 +02:00
|
|
|
#include "GPU/Vulkan/VulkanUtil.h"
|
|
|
|
|
|
|
|
#include "GPU/GPUState.h"
|
|
|
|
#include "GPU/Common/GPUDebugInterface.h"
|
|
|
|
#include "GPU/Common/IndexGenerator.h"
|
|
|
|
#include "GPU/Common/VertexDecoderCommon.h"
|
|
|
|
#include "GPU/Common/DrawEngineCommon.h"
|
|
|
|
#include "GPU/Common/GPUStateUtils.h"
|
2017-02-17 12:21:27 +01:00
|
|
|
#include "GPU/Vulkan/StateMappingVulkan.h"
|
2022-11-24 10:38:49 +01:00
|
|
|
#include "GPU/Vulkan/VulkanRenderManager.h"
|
2015-10-10 16:41:19 +02:00
|
|
|
|
|
|
|
struct DecVtxFormat;
|
|
|
|
struct UVScale;
|
|
|
|
|
|
|
|
class ShaderManagerVulkan;
|
|
|
|
class PipelineManagerVulkan;
|
|
|
|
class TextureCacheVulkan;
|
|
|
|
class FramebufferManagerVulkan;
|
|
|
|
|
2016-01-09 21:19:18 +01:00
|
|
|
class VulkanContext;
|
|
|
|
class VulkanPushBuffer;
|
2023-03-14 23:13:08 +01:00
|
|
|
class VulkanPushPool;
|
2017-08-14 16:02:58 +02:00
|
|
|
struct VulkanPipeline;
|
2016-01-09 21:19:18 +01:00
|
|
|
|
2016-03-31 10:23:40 +02:00
|
|
|
struct DrawEngineVulkanStats {
|
|
|
|
int pushVertexSpaceUsed;
|
|
|
|
int pushIndexSpaceUsed;
|
|
|
|
};
|
|
|
|
|
2017-08-17 11:22:23 +02:00
|
|
|
enum {
|
|
|
|
VAIVULKAN_FLAG_VERTEXFULLALPHA = 1,
|
|
|
|
};
|
|
|
|
|
|
|
|
// Try to keep this POD.
|
|
|
|
class VertexArrayInfoVulkan {
|
|
|
|
public:
|
|
|
|
VertexArrayInfoVulkan() {
|
|
|
|
lastFrame = gpuStats.numFlips;
|
|
|
|
}
|
|
|
|
// No destructor needed - we always fully wipe.
|
|
|
|
|
2017-12-13 23:11:40 +01:00
|
|
|
enum VAIStatus : uint8_t {
|
2017-08-17 11:22:23 +02:00
|
|
|
VAI_NEW,
|
|
|
|
VAI_HASHING,
|
|
|
|
VAI_RELIABLE, // cache, don't hash
|
|
|
|
VAI_UNRELIABLE, // never cache
|
|
|
|
};
|
|
|
|
|
2022-09-23 12:33:16 +02:00
|
|
|
uint64_t hash = 0;
|
|
|
|
u32 minihash = 0;
|
2017-08-17 11:22:23 +02:00
|
|
|
|
|
|
|
// These will probably always be the same, but whatever.
|
|
|
|
VkBuffer vb = VK_NULL_HANDLE;
|
|
|
|
VkBuffer ib = VK_NULL_HANDLE;
|
|
|
|
// Offsets into the cache buffer.
|
|
|
|
uint32_t vbOffset = 0;
|
|
|
|
uint32_t ibOffset = 0;
|
|
|
|
|
|
|
|
// Precalculated parameter for vkDrawIndexed
|
|
|
|
u16 numVerts = 0;
|
|
|
|
u16 maxIndex = 0;
|
|
|
|
s8 prim = GE_PRIM_INVALID;
|
2017-12-13 23:11:40 +01:00
|
|
|
VAIStatus status = VAI_NEW;
|
2017-08-17 11:22:23 +02:00
|
|
|
|
|
|
|
// ID information
|
|
|
|
int numDraws = 0;
|
|
|
|
int numFrames = 0;
|
|
|
|
int lastFrame; // So that we can forget.
|
|
|
|
u16 drawsUntilNextFullHash = 0;
|
|
|
|
u8 flags = 0;
|
|
|
|
};
|
|
|
|
|
2017-08-22 13:25:45 +02:00
|
|
|
class VulkanRenderManager;
|
|
|
|
|
2018-07-13 18:35:44 +09:00
|
|
|
class TessellationDataTransferVulkan : public TessellationDataTransfer {
|
|
|
|
public:
|
|
|
|
TessellationDataTransferVulkan(VulkanContext *vulkan) : vulkan_(vulkan) {}
|
|
|
|
|
2023-03-14 23:21:43 +01:00
|
|
|
void SetPushPool(VulkanPushPool *push) { push_ = push; }
|
2018-07-13 18:35:44 +09:00
|
|
|
// Send spline/bezier's control points and weights to vertex shader through structured shader buffer.
|
2018-09-29 13:39:02 +09:00
|
|
|
void SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Spline::Weight2D &weights) override;
|
2018-07-13 18:35:44 +09:00
|
|
|
const VkDescriptorBufferInfo *GetBufferInfo() { return bufInfo_; }
|
|
|
|
private:
|
|
|
|
VulkanContext *vulkan_;
|
2023-03-14 23:21:43 +01:00
|
|
|
VulkanPushPool *push_; // Updated each frame.
|
2018-07-13 18:35:44 +09:00
|
|
|
VkDescriptorBufferInfo bufInfo_[3]{};
|
|
|
|
};
|
|
|
|
|
2022-11-06 16:56:21 +01:00
|
|
|
enum {
|
|
|
|
DRAW_BINDING_TEXTURE = 0,
|
|
|
|
DRAW_BINDING_2ND_TEXTURE = 1,
|
|
|
|
DRAW_BINDING_DEPAL_TEXTURE = 2,
|
|
|
|
DRAW_BINDING_DYNUBO_BASE = 3,
|
|
|
|
DRAW_BINDING_DYNUBO_LIGHT = 4,
|
|
|
|
DRAW_BINDING_DYNUBO_BONE = 5,
|
|
|
|
DRAW_BINDING_TESS_STORAGE_BUF = 6,
|
|
|
|
DRAW_BINDING_TESS_STORAGE_BUF_WU = 7,
|
|
|
|
DRAW_BINDING_TESS_STORAGE_BUF_WV = 8,
|
2023-06-13 20:46:27 +02:00
|
|
|
DRAW_BINDING_COUNT = 9,
|
2022-11-06 16:56:21 +01:00
|
|
|
};
|
|
|
|
|
2015-10-10 16:41:19 +02:00
|
|
|
// Handles transform, lighting and drawing.
|
|
|
|
class DrawEngineVulkan : public DrawEngineCommon {
|
|
|
|
public:
|
2021-11-14 15:25:28 -08:00
|
|
|
DrawEngineVulkan(Draw::DrawContext *draw);
|
2022-12-10 20:32:12 -08:00
|
|
|
~DrawEngineVulkan();
|
2015-10-10 16:41:19 +02:00
|
|
|
|
2022-10-01 20:01:23 -07:00
|
|
|
// We reference feature flags, so this is called after construction.
|
|
|
|
void InitDeviceObjects();
|
|
|
|
|
2015-10-10 16:41:19 +02:00
|
|
|
void SetShaderManager(ShaderManagerVulkan *shaderManager) {
|
|
|
|
shaderManager_ = shaderManager;
|
|
|
|
}
|
|
|
|
void SetPipelineManager(PipelineManagerVulkan *pipelineManager) {
|
|
|
|
pipelineManager_ = pipelineManager;
|
|
|
|
}
|
|
|
|
void SetTextureCache(TextureCacheVulkan *textureCache) {
|
|
|
|
textureCache_ = textureCache;
|
|
|
|
}
|
|
|
|
void SetFramebufferManager(FramebufferManagerVulkan *fbManager) {
|
|
|
|
framebufferManager_ = fbManager;
|
|
|
|
}
|
|
|
|
|
2023-02-26 11:05:52 +01:00
|
|
|
void DeviceLost() override;
|
|
|
|
void DeviceRestore(Draw::DrawContext *draw) override;
|
2015-10-10 16:41:19 +02:00
|
|
|
|
|
|
|
// So that this can be inlined
|
2017-05-19 17:21:08 +02:00
|
|
|
void Flush() {
|
2023-05-23 18:00:50 +02:00
|
|
|
if (!numDrawCalls_)
|
2015-10-10 16:41:19 +02:00
|
|
|
return;
|
2017-05-19 17:21:08 +02:00
|
|
|
DoFlush();
|
2015-10-10 16:41:19 +02:00
|
|
|
}
|
|
|
|
|
2017-11-16 16:27:24 +01:00
|
|
|
void FinishDeferred() {
|
2023-05-23 18:00:50 +02:00
|
|
|
if (!numDrawCalls_)
|
2017-11-16 16:27:24 +01:00
|
|
|
return;
|
|
|
|
// Decode any pending vertices. And also flush while we're at it, for simplicity.
|
|
|
|
// It might be possible to only decode like in the other backends, but meh, it can't matter.
|
|
|
|
// Issue #10095 has a nice example of where this is required.
|
|
|
|
DoFlush();
|
|
|
|
}
|
|
|
|
|
2023-05-03 22:49:59 +02:00
|
|
|
void DispatchFlush() override {
|
2023-05-23 18:00:50 +02:00
|
|
|
if (!numDrawCalls_)
|
2023-05-03 22:49:59 +02:00
|
|
|
return;
|
|
|
|
Flush();
|
|
|
|
}
|
2015-10-10 16:41:19 +02:00
|
|
|
|
2016-01-03 18:31:03 +01:00
|
|
|
VkPipelineLayout GetPipelineLayout() const {
|
|
|
|
return pipelineLayout_;
|
|
|
|
}
|
|
|
|
|
2016-01-06 12:52:42 +01:00
|
|
|
void BeginFrame();
|
2016-01-03 18:31:03 +01:00
|
|
|
void EndFrame();
|
|
|
|
|
2016-03-20 16:33:34 +01:00
|
|
|
void DirtyAllUBOs();
|
|
|
|
|
2017-08-22 13:25:45 +02:00
|
|
|
void DirtyPipeline() {
|
|
|
|
lastPipeline_ = nullptr;
|
|
|
|
}
|
|
|
|
|
2023-03-14 23:21:43 +01:00
|
|
|
VulkanPushPool *GetPushBufferForTextureData() {
|
2023-03-15 10:09:39 +01:00
|
|
|
return pushUBO_;
|
2016-03-28 22:14:04 +02:00
|
|
|
}
|
|
|
|
|
2016-03-31 10:23:40 +02:00
|
|
|
const DrawEngineVulkanStats &GetStats() const {
|
|
|
|
return stats_;
|
|
|
|
}
|
|
|
|
|
2022-08-24 09:31:47 +02:00
|
|
|
void SetDepalTexture(VkImageView depal, bool smooth) {
|
2018-05-04 22:20:41 +02:00
|
|
|
if (boundDepal_ != depal) {
|
|
|
|
boundDepal_ = depal;
|
2022-08-24 09:31:47 +02:00
|
|
|
boundDepalSmoothed_ = smooth;
|
2018-05-04 22:20:41 +02:00
|
|
|
gstate_c.Dirty(DIRTY_FRAGMENTSHADER_STATE);
|
|
|
|
}
|
2018-04-13 12:25:57 +02:00
|
|
|
}
|
2017-11-12 10:17:49 +01:00
|
|
|
|
2015-10-10 16:41:19 +02:00
|
|
|
private:
|
2022-12-01 19:15:38 +01:00
|
|
|
void Invalidate(InvalidationCallbackFlags flags);
|
2022-11-24 10:38:49 +01:00
|
|
|
|
2016-03-20 15:13:17 -07:00
|
|
|
struct FrameData;
|
2017-08-22 13:25:45 +02:00
|
|
|
void ApplyDrawStateLate(VulkanRenderManager *renderManager, bool applyStencilRef, uint8_t stencilRef, bool useBlendConstant);
|
2017-02-17 12:21:27 +01:00
|
|
|
void ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManager, ShaderManagerVulkan *shaderManager, int prim, VulkanPipelineRasterStateKey &key, VulkanDynamicState &dynState);
|
2017-11-15 20:43:29 +01:00
|
|
|
void BindShaderBlendTex();
|
2017-02-17 12:21:27 +01:00
|
|
|
|
2016-10-09 10:53:01 -07:00
|
|
|
void DestroyDeviceObjects();
|
|
|
|
|
2023-06-05 10:47:20 +02:00
|
|
|
bool VertexCacheLookup(int &vertexCount, GEPrimitiveType &prim, VkBuffer &vbuf, uint32_t &vbOffset, VkBuffer &ibuf, uint32_t &ibOffset, bool &useElements, bool forceIndexed);
|
|
|
|
|
2023-03-14 23:13:08 +01:00
|
|
|
void DecodeVertsToPushPool(VulkanPushPool *push, uint32_t *bindOffset, VkBuffer *vkbuf);
|
2017-11-19 12:33:20 +01:00
|
|
|
void DecodeVertsToPushBuffer(VulkanPushBuffer *push, uint32_t *bindOffset, VkBuffer *vkbuf);
|
2016-03-21 18:50:11 +01:00
|
|
|
|
2017-05-19 17:21:08 +02:00
|
|
|
void DoFlush();
|
2016-03-20 15:13:17 -07:00
|
|
|
void UpdateUBOs(FrameData *frame);
|
2021-11-14 15:25:28 -08:00
|
|
|
FrameData &GetCurFrame();
|
2015-10-10 16:41:19 +02:00
|
|
|
|
2018-04-10 12:22:02 +02:00
|
|
|
VkDescriptorSet GetOrCreateDescriptorSet(VkImageView imageView, VkSampler sampler, VkBuffer base, VkBuffer light, VkBuffer bone, bool tess);
|
2016-01-03 18:31:03 +01:00
|
|
|
|
2017-05-19 17:21:08 +02:00
|
|
|
Draw::DrawContext *draw_;
|
2016-01-03 18:31:03 +01:00
|
|
|
|
2022-10-28 09:23:44 +02:00
|
|
|
// We use a shared descriptor set layouts for all PSP draws.
|
|
|
|
// Descriptors created from descriptorSetLayout_ is rebound all the time at set 1.
|
2016-01-03 18:31:03 +01:00
|
|
|
VkDescriptorSetLayout descriptorSetLayout_;
|
2022-10-18 00:26:10 +02:00
|
|
|
|
2016-01-03 18:31:03 +01:00
|
|
|
VkPipelineLayout pipelineLayout_;
|
2017-08-14 16:02:58 +02:00
|
|
|
VulkanPipeline *lastPipeline_;
|
2017-08-18 13:39:42 +02:00
|
|
|
VkDescriptorSet lastDs_ = VK_NULL_HANDLE;
|
2016-01-03 18:31:03 +01:00
|
|
|
|
2017-10-31 12:02:10 +01:00
|
|
|
// Secondary texture for shader blending
|
|
|
|
VkImageView boundSecondary_ = VK_NULL_HANDLE;
|
2022-09-16 19:18:38 +02:00
|
|
|
|
2022-08-24 09:31:47 +02:00
|
|
|
// CLUT texture for shader depal
|
2018-04-13 12:25:57 +02:00
|
|
|
VkImageView boundDepal_ = VK_NULL_HANDLE;
|
2022-08-24 09:31:47 +02:00
|
|
|
bool boundDepalSmoothed_ = false;
|
|
|
|
VkSampler samplerSecondaryLinear_ = VK_NULL_HANDLE;
|
|
|
|
VkSampler samplerSecondaryNearest_ = VK_NULL_HANDLE;
|
2017-10-31 12:02:10 +01:00
|
|
|
|
2023-09-11 12:02:56 +02:00
|
|
|
PrehashMap<VertexArrayInfoVulkan *> vai_;
|
2017-08-17 11:22:23 +02:00
|
|
|
VulkanPushBuffer *vertexCache_;
|
2017-08-20 21:35:03 +02:00
|
|
|
int descDecimationCounter_ = 0;
|
2017-08-17 11:22:23 +02:00
|
|
|
|
2016-01-06 12:52:42 +01:00
|
|
|
struct DescriptorSetKey {
|
2016-01-09 21:19:18 +01:00
|
|
|
VkImageView imageView_;
|
|
|
|
VkImageView secondaryImageView_;
|
2018-04-13 12:25:57 +02:00
|
|
|
VkImageView depalImageView_;
|
2016-01-09 01:23:32 +01:00
|
|
|
VkSampler sampler_;
|
2018-04-10 12:22:02 +02:00
|
|
|
VkBuffer base_, light_, bone_; // All three UBO slots will be set to this. This will usually be identical
|
2016-01-09 21:19:18 +01:00
|
|
|
// for all draws in a frame, except when the buffer has to grow.
|
2016-01-06 12:52:42 +01:00
|
|
|
};
|
|
|
|
|
2016-01-03 18:31:03 +01:00
|
|
|
// We alternate between these.
|
|
|
|
struct FrameData {
|
2021-12-09 18:39:55 -08:00
|
|
|
FrameData() : descSets(512), descPool("DrawEngine", true) {
|
|
|
|
descPool.Setup([this] { descSets.Clear(); });
|
|
|
|
}
|
2017-08-20 11:30:19 +02:00
|
|
|
|
2021-12-09 18:39:55 -08:00
|
|
|
VulkanDescSetPool descPool;
|
2018-02-24 10:24:11 +01:00
|
|
|
|
2016-01-06 12:52:42 +01:00
|
|
|
// We do rolling allocation and reset instead of caching across frames. That we might do later.
|
2023-09-11 12:02:56 +02:00
|
|
|
DenseHashMap<DescriptorSetKey, VkDescriptorSet> descSets;
|
2016-10-09 10:53:01 -07:00
|
|
|
|
|
|
|
void Destroy(VulkanContext *vulkan);
|
2016-01-03 18:31:03 +01:00
|
|
|
};
|
|
|
|
|
2017-08-15 16:01:50 +02:00
|
|
|
GEPrimitiveType lastPrim_ = GE_PRIM_INVALID;
|
2017-08-17 17:55:21 +02:00
|
|
|
FrameData frame_[VulkanContext::MAX_INFLIGHT_FRAMES];
|
2016-01-03 18:31:03 +01:00
|
|
|
|
2023-03-15 10:09:39 +01:00
|
|
|
// This one's not accurately named, it's used for all kinds of stuff that's not vertices or indices.
|
|
|
|
VulkanPushPool *pushUBO_ = nullptr;
|
|
|
|
|
|
|
|
VulkanPushPool *pushVertex_ = nullptr;
|
|
|
|
VulkanPushPool *pushIndex_ = nullptr;
|
2023-03-14 23:13:08 +01:00
|
|
|
|
2015-10-10 16:41:19 +02:00
|
|
|
// Other
|
2017-02-17 12:21:18 +01:00
|
|
|
ShaderManagerVulkan *shaderManager_ = nullptr;
|
|
|
|
PipelineManagerVulkan *pipelineManager_ = nullptr;
|
|
|
|
TextureCacheVulkan *textureCache_ = nullptr;
|
|
|
|
FramebufferManagerVulkan *framebufferManager_ = nullptr;
|
2015-10-10 16:41:19 +02:00
|
|
|
|
2016-03-20 22:46:49 +01:00
|
|
|
// State cache
|
2017-01-24 20:00:03 +01:00
|
|
|
uint64_t dirtyUniforms_;
|
2016-03-20 16:33:34 +01:00
|
|
|
uint32_t baseUBOOffset;
|
|
|
|
uint32_t lightUBOOffset;
|
2018-04-10 12:22:02 +02:00
|
|
|
uint32_t boneUBOOffset;
|
|
|
|
VkBuffer baseBuf, lightBuf, boneBuf;
|
2017-10-31 12:02:10 +01:00
|
|
|
VkImageView imageView = VK_NULL_HANDLE;
|
|
|
|
VkSampler sampler = VK_NULL_HANDLE;
|
2016-03-20 22:46:49 +01:00
|
|
|
|
2018-06-01 18:51:37 +02:00
|
|
|
// For null texture
|
2017-06-02 11:47:14 +02:00
|
|
|
VkSampler nullSampler_ = VK_NULL_HANDLE;
|
2016-03-20 16:33:34 +01:00
|
|
|
|
2021-02-15 10:29:34 -08:00
|
|
|
DrawEngineVulkanStats stats_{};
|
2017-01-10 14:41:01 +09:00
|
|
|
|
2017-04-03 17:26:54 +02:00
|
|
|
VulkanPipelineRasterStateKey pipelineKey_{};
|
|
|
|
VulkanDynamicState dynState_{};
|
|
|
|
|
2017-11-12 12:07:33 +01:00
|
|
|
int tessOffset_ = 0;
|
2022-02-19 20:40:27 +01:00
|
|
|
FBOTexState fboTexBindState_ = FBO_TEX_NONE;
|
2017-11-12 12:07:33 +01:00
|
|
|
|
2017-01-10 14:41:01 +09:00
|
|
|
// Hardware tessellation
|
2018-07-11 01:09:20 +09:00
|
|
|
TessellationDataTransferVulkan *tessDataTransferVulkan;
|
2015-10-10 16:41:19 +02:00
|
|
|
};
|