mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-19 09:19:05 +02:00
Some reorganization. Start implementing framebuffer depal for Vulkan.
This commit is contained in:
1 parent
6253280fba
commit
65e23bb9f3
13 files changed
+295
-161
No files matched your search
@@ -20,4 +20,6 @@
|
||||
#include "GPU/ge_constants.h"
|
||||
#include "GPU/Common/ShaderCommon.h"
|
||||
|
||||
static const int DEPAL_TEXTURE_OLD_AGE = 120;
|
||||
|
||||
void GenerateDepalShader(char *buffer, GEBufferFormat pixelFormat, ShaderLanguage language);
|
||||
@@ -29,8 +29,6 @@
|
||||
#include "GPU/D3D11/D3D11Util.h"
|
||||
#include "GPU/Common/DepalettizeShaderCommon.h"
|
||||
|
||||
static const int DEPAL_TEXTURE_OLD_AGE = 120;
|
||||
|
||||
#ifdef _WIN32
|
||||
#define SHADERLOG
|
||||
#endif
|
||||
|
||||
@@ -26,8 +26,6 @@
|
||||
#include "ext/native/gfx/GLStateCache.h"
|
||||
#include "GPU/Common/DepalettizeShaderCommon.h"
|
||||
|
||||
static const int DEPAL_TEXTURE_OLD_AGE = 120;
|
||||
|
||||
#ifdef _WIN32
|
||||
#define SHADERLOG
|
||||
#endif
|
||||
|
||||
@@ -15,10 +15,29 @@
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
|
||||
#include "Common/Vulkan/VulkanContext.h"
|
||||
#include "GPU/GPUState.h"
|
||||
#include "GPU/Common/DepalettizeShaderCommon.h"
|
||||
#include "GPU/Vulkan/DepalettizeShaderVulkan.h"
|
||||
#include "GPU/Vulkan/VulkanUtil.h"
|
||||
#include "Common/Vulkan/VulkanImage.h"
|
||||
|
||||
DepalShaderCacheVulkan::DepalShaderCacheVulkan() {
|
||||
static VkFormat GetClutDestFormat(GEPaletteFormat format) {
|
||||
switch (format) {
|
||||
case GE_CMODE_16BIT_ABGR4444:
|
||||
return VK_FORMAT_R4G4B4A4_UNORM_PACK16;
|
||||
case GE_CMODE_16BIT_ABGR5551:
|
||||
return VK_FORMAT_A1R5G5B5_UNORM_PACK16;
|
||||
case GE_CMODE_16BIT_BGR5650:
|
||||
return VK_FORMAT_R5G6B5_UNORM_PACK16;
|
||||
case GE_CMODE_32BIT_ABGR8888:
|
||||
return VK_FORMAT_R8G8B8A8_UNORM;
|
||||
}
|
||||
return VK_FORMAT_UNDEFINED;
|
||||
}
|
||||
|
||||
DepalShaderCacheVulkan::DepalShaderCacheVulkan(Draw::DrawContext *draw, VulkanContext *vulkan)
|
||||
: draw_(draw), vulkan_(vulkan) {
|
||||
|
||||
}
|
||||
|
||||
@@ -26,22 +45,94 @@ DepalShaderCacheVulkan::~DepalShaderCacheVulkan() {
|
||||
|
||||
}
|
||||
|
||||
DepalShaderVulkan *DepalShaderCacheVulkan::GetDepalettizeShader(GEPaletteFormat clutFormat, GEBufferFormat pixelFormat) {
|
||||
DepalShaderVulkan *DepalShaderCacheVulkan::GetDepalettizeShader(uint32_t clutMode, GEBufferFormat pixelFormat) {
|
||||
u32 id = GenerateShaderID(clutMode, pixelFormat);
|
||||
|
||||
auto shader = cache_.find(id);
|
||||
if (shader != cache_.end()) {
|
||||
return shader->second;
|
||||
}
|
||||
|
||||
char *buffer = new char[2048];
|
||||
|
||||
VkRenderPass rp = (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::FRAMEBUFFER_RENDERPASS);
|
||||
|
||||
GenerateDepalShader(buffer, pixelFormat, GLSL_VULKAN);
|
||||
|
||||
std::string error;
|
||||
VkShaderModule fshader = CompileShaderModule(vulkan_, VK_SHADER_STAGE_FRAGMENT_BIT, buffer, &error);
|
||||
if (fshader == VK_NULL_HANDLE) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
VkPipeline pipeline = vulkan2D_->GetPipeline(rp, vshader_, fshader);
|
||||
// Can delete the shader module now that the pipeline has been created.
|
||||
// Maybe don't even need to queue it..
|
||||
vulkan_->Delete().QueueDeleteShaderModule(fshader);
|
||||
|
||||
DepalShaderVulkan *depal = new DepalShaderVulkan();
|
||||
depal->pipeline = pipeline;
|
||||
depal->code = buffer;
|
||||
cache_[id] = depal;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
VulkanTexture *DepalShaderCacheVulkan::GetClutTexture(GEPaletteFormat clutFormat, const u32 clutHash, u32 *rawClut) {
|
||||
return nullptr;
|
||||
VulkanTexture *DepalShaderCacheVulkan::GetClutTexture(GEPaletteFormat clutFormat, u32 clutID, u32 *rawClut) {
|
||||
const u32 realClutID = clutID ^ clutFormat;
|
||||
|
||||
auto oldtex = texCache_.find(realClutID);
|
||||
if (oldtex != texCache_.end()) {
|
||||
oldtex->second->lastFrame = gpuStats.numFlips;
|
||||
return oldtex->second->texture;
|
||||
}
|
||||
|
||||
VkFormat destFormat = GetClutDestFormat(clutFormat);
|
||||
int texturePixels = clutFormat == GE_CMODE_32BIT_ABGR8888 ? 256 : 512;
|
||||
|
||||
VkBuffer pushBuffer;
|
||||
uint32_t pushOffset = push_->PushAligned(rawClut, 1024, 4, &pushBuffer);
|
||||
|
||||
VulkanTexture *vktex = new VulkanTexture(vulkan_, alloc_);
|
||||
vktex->CreateDirect(cmd_, texturePixels, 1, 1, destFormat, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_USAGE_SAMPLED_BIT, nullptr);
|
||||
vktex->UploadMip(cmd_, 0, texturePixels, 1, pushBuffer, pushOffset, texturePixels);
|
||||
vktex->EndCreate(cmd_);
|
||||
|
||||
DepalTextureVulkan *tex = new DepalTextureVulkan();
|
||||
tex->texture = vktex;
|
||||
tex->lastFrame = gpuStats.numFlips;
|
||||
texCache_[realClutID] = tex;
|
||||
return tex->texture;
|
||||
}
|
||||
|
||||
void DepalShaderCacheVulkan::Clear() {}
|
||||
void DepalShaderCacheVulkan::Clear() {
|
||||
for (auto shader = cache_.begin(); shader != cache_.end(); ++shader) {
|
||||
// Delete the shader/pipeline too.
|
||||
delete shader->second;
|
||||
}
|
||||
cache_.clear();
|
||||
|
||||
void DepalShaderCacheVulkan::Decimate() {}
|
||||
for (auto tex = texCache_.begin(); tex != texCache_.end(); ++tex) {
|
||||
delete tex->second->texture;
|
||||
delete tex->second;
|
||||
}
|
||||
texCache_.clear();
|
||||
|
||||
u32 DepalShaderCacheVulkan::GenerateShaderID(GEPaletteFormat clutFormat, GEBufferFormat pixelFormat) {
|
||||
return 0;
|
||||
// TODO: Delete vertex shader.
|
||||
}
|
||||
|
||||
bool DepalShaderCacheVulkan::CreateVertexShader() {
|
||||
return false;
|
||||
void DepalShaderCacheVulkan::Decimate() {
|
||||
// We don't bother decimating the generated shaders, there are never very many of them.
|
||||
for (auto tex = texCache_.begin(); tex != texCache_.end(); ) {
|
||||
if (tex->second->lastFrame + DEPAL_TEXTURE_OLD_AGE < gpuStats.numFlips) {
|
||||
delete tex->second->texture;
|
||||
delete tex->second;
|
||||
texCache_.erase(tex++);
|
||||
} else {
|
||||
++tex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 DepalShaderCacheVulkan::GenerateShaderID(uint32_t clutMode, GEBufferFormat pixelFormat) {
|
||||
return (clutMode & 0xFFFFFF) | (pixelFormat << 24);
|
||||
}
|
||||
@@ -20,42 +20,59 @@
|
||||
#include <map>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Vulkan/VulkanContext.h"
|
||||
#include "Common/Vulkan/VulkanImage.h"
|
||||
#include "Common/Vulkan/VulkanMemory.h"
|
||||
#include "GPU/ge_constants.h"
|
||||
#include "thin3d/thin3d.h"
|
||||
|
||||
class DepalShaderVulkan {
|
||||
public:
|
||||
/*
|
||||
GLuint program;
|
||||
GLuint fragShader;
|
||||
GLint a_position;
|
||||
GLint a_texcoord0;
|
||||
*/
|
||||
~DepalShaderVulkan() {
|
||||
delete[] code;
|
||||
}
|
||||
// A Vulkan2D pipeline. Set texture to slot 0 and palette texture to slot 1.
|
||||
VkPipeline pipeline;
|
||||
const char *code = nullptr;;
|
||||
};
|
||||
|
||||
class DepalTextureVulkan {
|
||||
public:
|
||||
int texture;
|
||||
VulkanTexture *texture;
|
||||
int lastFrame;
|
||||
};
|
||||
|
||||
class VulkanTexture;
|
||||
class Vulkan2D;
|
||||
|
||||
// Caches both shaders and palette textures.
|
||||
// Could even avoid bothering with palette texture and just use uniform data...
|
||||
class DepalShaderCacheVulkan {
|
||||
public:
|
||||
DepalShaderCacheVulkan();
|
||||
DepalShaderCacheVulkan(Draw::DrawContext *draw, VulkanContext *vulkan);
|
||||
~DepalShaderCacheVulkan();
|
||||
|
||||
// This also uploads the palette and binds the correct texture.
|
||||
DepalShaderVulkan *GetDepalettizeShader(GEPaletteFormat clutFormat, GEBufferFormat pixelFormat);
|
||||
DepalShaderVulkan *GetDepalettizeShader(uint32_t clutMode, GEBufferFormat pixelFormat);
|
||||
VulkanTexture *GetClutTexture(GEPaletteFormat clutFormat, const u32 clutHash, u32 *rawClut);
|
||||
void Clear();
|
||||
void Decimate();
|
||||
|
||||
void SetVulkan2D(Vulkan2D *vk2d) { vulkan2D_ = vk2d; }
|
||||
void SetPushBuffer(VulkanPushBuffer *push) { push_ = push; }
|
||||
void SetAllocator(VulkanDeviceAllocator *alloc) { alloc_ = alloc; }
|
||||
void SetVShader(VkShaderModule vshader) { vshader_ = vshader; }
|
||||
|
||||
private:
|
||||
u32 GenerateShaderID(GEPaletteFormat clutFormat, GEBufferFormat pixelFormat);
|
||||
bool CreateVertexShader();
|
||||
u32 GenerateShaderID(uint32_t clutMode, GEBufferFormat pixelFormat);
|
||||
|
||||
VkCommandBuffer cmd_ = VK_NULL_HANDLE;
|
||||
Draw::DrawContext *draw_ = nullptr;
|
||||
VulkanContext *vulkan_ = nullptr;
|
||||
VulkanPushBuffer *push_ = nullptr;
|
||||
VulkanDeviceAllocator *alloc_ = nullptr;
|
||||
VkShaderModule vshader_ = VK_NULL_HANDLE;
|
||||
Vulkan2D *vulkan2D_ = nullptr;
|
||||
|
||||
// GLuint vertexShader_;
|
||||
std::map<u32, DepalShaderVulkan *> cache_;
|
||||
|
||||
@@ -88,9 +88,8 @@ FramebufferManagerVulkan::FramebufferManagerVulkan(Draw::DrawContext *draw, Vulk
|
||||
convBufSize_(0),
|
||||
textureCacheVulkan_(nullptr),
|
||||
shaderManagerVulkan_(nullptr),
|
||||
curFrame_(0),
|
||||
pipelinePostShader_(VK_NULL_HANDLE),
|
||||
vulkan2D_(vulkan) {
|
||||
depalVulkan_(draw, vulkan) {
|
||||
|
||||
InitDeviceObjects();
|
||||
|
||||
@@ -101,7 +100,6 @@ FramebufferManagerVulkan::FramebufferManagerVulkan(Draw::DrawContext *draw, Vulk
|
||||
FramebufferManagerVulkan::~FramebufferManagerVulkan() {
|
||||
delete[] convBuf_;
|
||||
|
||||
vulkan2D_.Shutdown();
|
||||
DestroyDeviceObjects();
|
||||
}
|
||||
|
||||
@@ -121,23 +119,12 @@ void FramebufferManagerVulkan::SetDrawEngine(DrawEngineVulkan *td) {
|
||||
}
|
||||
|
||||
void FramebufferManagerVulkan::InitDeviceObjects() {
|
||||
// Initialize framedata
|
||||
for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) {
|
||||
frameData_[i].push_ = new VulkanPushBuffer(vulkan_, 64 * 1024);
|
||||
}
|
||||
|
||||
pipelineCache2D_ = vulkan_->CreatePipelineCache();
|
||||
|
||||
std::string fs_errors, vs_errors;
|
||||
fsBasicTex_ = CompileShaderModule(vulkan_, VK_SHADER_STAGE_FRAGMENT_BIT, tex_fs, &fs_errors);
|
||||
vsBasicTex_ = CompileShaderModule(vulkan_, VK_SHADER_STAGE_VERTEX_BIT, tex_vs, &vs_errors);
|
||||
assert(fsBasicTex_ != VK_NULL_HANDLE);
|
||||
assert(vsBasicTex_ != VK_NULL_HANDLE);
|
||||
|
||||
// Prime the 2D pipeline cache.
|
||||
// vulkan2D_.GetPipeline(pipelineCache2D_, (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::BACKBUFFER_RENDERPASS), vsBasicTex_, fsBasicTex_);
|
||||
// vulkan2D_.GetPipeline(pipelineCache2D_, (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::FRAMEBUFFER_RENDERPASS), vsBasicTex_, fsBasicTex_);
|
||||
|
||||
VkSamplerCreateInfo samp = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
|
||||
samp.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
samp.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
@@ -153,13 +140,6 @@ void FramebufferManagerVulkan::InitDeviceObjects() {
|
||||
}
|
||||
|
||||
void FramebufferManagerVulkan::DestroyDeviceObjects() {
|
||||
for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) {
|
||||
if (frameData_[i].push_) {
|
||||
frameData_[i].push_->Destroy(vulkan_);
|
||||
delete frameData_[i].push_;
|
||||
frameData_[i].push_ = nullptr;
|
||||
}
|
||||
}
|
||||
delete drawPixelsTex_;
|
||||
drawPixelsTex_ = nullptr;
|
||||
|
||||
@@ -172,32 +152,29 @@ void FramebufferManagerVulkan::DestroyDeviceObjects() {
|
||||
vulkan_->Delete().QueueDeleteSampler(linearSampler_);
|
||||
if (nearestSampler_ != VK_NULL_HANDLE)
|
||||
vulkan_->Delete().QueueDeleteSampler(nearestSampler_);
|
||||
// pipelineBasicTex_ and pipelineBasicTex_ come from vulkan2D_.
|
||||
if (pipelineCache2D_ != VK_NULL_HANDLE)
|
||||
vulkan_->Delete().QueueDeletePipelineCache(pipelineCache2D_);
|
||||
}
|
||||
|
||||
void FramebufferManagerVulkan::NotifyClear(bool clearColor, bool clearAlpha, bool clearDepth, uint32_t color, float depth) {
|
||||
float x, y, w, h;
|
||||
CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)pixelWidth_, (float)pixelHeight_, ROTATION_LOCKED_HORIZONTAL);
|
||||
float x, y, w, h;
|
||||
CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)pixelWidth_, (float)pixelHeight_, ROTATION_LOCKED_HORIZONTAL);
|
||||
|
||||
int mask = 0;
|
||||
// The Clear detection takes care of doing a regular draw instead if separate masking
|
||||
// of color and alpha is needed, so we can just treat them as the same.
|
||||
if (clearColor || clearAlpha)
|
||||
mask |= Draw::FBChannel::FB_COLOR_BIT;
|
||||
if (clearDepth)
|
||||
mask |= Draw::FBChannel::FB_DEPTH_BIT;
|
||||
if (clearAlpha)
|
||||
mask |= Draw::FBChannel::FB_STENCIL_BIT;
|
||||
int mask = 0;
|
||||
// The Clear detection takes care of doing a regular draw instead if separate masking
|
||||
// of color and alpha is needed, so we can just treat them as the same.
|
||||
if (clearColor || clearAlpha)
|
||||
mask |= Draw::FBChannel::FB_COLOR_BIT;
|
||||
if (clearDepth)
|
||||
mask |= Draw::FBChannel::FB_DEPTH_BIT;
|
||||
if (clearAlpha)
|
||||
mask |= Draw::FBChannel::FB_STENCIL_BIT;
|
||||
|
||||
draw_->Clear(mask, color, depth, 0);
|
||||
if (clearColor || clearAlpha) {
|
||||
SetColorUpdated(gstate_c.skipDrawReason);
|
||||
}
|
||||
if (clearDepth) {
|
||||
SetDepthUpdated();
|
||||
}
|
||||
draw_->Clear(mask, color, depth, 0);
|
||||
if (clearColor || clearAlpha) {
|
||||
SetColorUpdated(gstate_c.skipDrawReason);
|
||||
}
|
||||
if (clearDepth) {
|
||||
SetDepthUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
void FramebufferManagerVulkan::UpdatePostShaderUniforms(int bufferWidth, int bufferHeight, int renderWidth, int renderHeight) {
|
||||
@@ -242,6 +219,7 @@ void FramebufferManagerVulkan::MakePixelTexture(const u8 *srcPixels, GEBufferFor
|
||||
// Initialize backbuffer texture for DrawPixels
|
||||
drawPixelsTexFormat_ = srcPixelFormat;
|
||||
} else {
|
||||
// TODO: We may want to double-buffer these, when we have more frames hanging about.
|
||||
drawPixelsTex_->TransitionForUpload(initCmd);
|
||||
}
|
||||
|
||||
@@ -298,7 +276,7 @@ void FramebufferManagerVulkan::MakePixelTexture(const u8 *srcPixels, GEBufferFor
|
||||
}
|
||||
|
||||
VkBuffer buffer;
|
||||
size_t offset = frameData_[curFrame_].push_->Push(data, width * height * 4, &buffer);
|
||||
size_t offset = push_->Push(data, width * height * 4, &buffer);
|
||||
drawPixelsTex_->UploadMip(initCmd, 0, width, height, buffer, (uint32_t)offset, width);
|
||||
drawPixelsTex_->EndCreate(initCmd);
|
||||
|
||||
@@ -357,22 +335,21 @@ void FramebufferManagerVulkan::DrawActiveTexture(float x, float y, float w, floa
|
||||
|
||||
// TODO: Should probably use draw_ directly and not go low level
|
||||
|
||||
VulkanPushBuffer *push = frameData_[curFrame_].push_;
|
||||
VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
|
||||
|
||||
VkImageView view = overrideImageView_ ? overrideImageView_ : (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE_IMAGEVIEW);
|
||||
if ((flags & DRAWTEX_KEEP_TEX) == 0)
|
||||
overrideImageView_ = VK_NULL_HANDLE;
|
||||
VkDescriptorSet descSet = vulkan2D_.GetDescriptorSet(view, (flags & DRAWTEX_LINEAR) ? linearSampler_ : nearestSampler_, VK_NULL_HANDLE, VK_NULL_HANDLE);
|
||||
VkDescriptorSet descSet = vulkan2D_->GetDescriptorSet(view, (flags & DRAWTEX_LINEAR) ? linearSampler_ : nearestSampler_, VK_NULL_HANDLE, VK_NULL_HANDLE);
|
||||
VkBuffer vbuffer;
|
||||
VkDeviceSize offset = push->Push(vtx, sizeof(vtx), &vbuffer);
|
||||
VkDeviceSize offset = push_->Push(vtx, sizeof(vtx), &vbuffer);
|
||||
renderManager->BindPipeline(cur2DPipeline_);
|
||||
renderManager->Draw(vulkan2D_.GetPipelineLayout(), descSet, 0, nullptr, vbuffer, offset, 4);
|
||||
renderManager->Draw(vulkan2D_->GetPipelineLayout(), descSet, 0, nullptr, vbuffer, offset, 4);
|
||||
}
|
||||
|
||||
void FramebufferManagerVulkan::Bind2DShader() {
|
||||
VkRenderPass rp = (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::COMPATIBLE_RENDERPASS);
|
||||
cur2DPipeline_ = vulkan2D_.GetPipeline(pipelineCache2D_, rp, vsBasicTex_, fsBasicTex_);
|
||||
cur2DPipeline_ = vulkan2D_->GetPipeline(rp, vsBasicTex_, fsBasicTex_);
|
||||
}
|
||||
|
||||
void FramebufferManagerVulkan::BindPostShader(const PostShaderUniforms &uniforms) {
|
||||
@@ -608,31 +585,13 @@ void ConvertFromRGBA8888_Vulkan(u8 *dst, const u8 *src, u32 dstStride, u32 srcSt
|
||||
|
||||
void FramebufferManagerVulkan::BeginFrameVulkan() {
|
||||
BeginFrame();
|
||||
|
||||
vulkan2D_.BeginFrame();
|
||||
|
||||
FrameData &frame = frameData_[curFrame_];
|
||||
|
||||
frame.push_->Reset();
|
||||
frame.push_->Begin(vulkan_);
|
||||
}
|
||||
|
||||
void FramebufferManagerVulkan::EndFrame() {
|
||||
// We flush to memory last requested framebuffer, if any.
|
||||
// Only do this in the read-framebuffer modes.
|
||||
FrameData &frame = frameData_[curFrame_];
|
||||
frame.push_->End();
|
||||
|
||||
vulkan2D_.EndFrame();
|
||||
|
||||
curFrame_++;
|
||||
if (curFrame_ >= vulkan_->GetInflightFrames()) {
|
||||
curFrame_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void FramebufferManagerVulkan::DeviceLost() {
|
||||
vulkan2D_.DeviceLost();
|
||||
vulkan2D_->DeviceLost();
|
||||
|
||||
DestroyAllFBOs();
|
||||
DestroyDeviceObjects();
|
||||
@@ -641,7 +600,7 @@ void FramebufferManagerVulkan::DeviceLost() {
|
||||
void FramebufferManagerVulkan::DeviceRestore(VulkanContext *vulkan) {
|
||||
vulkan_ = vulkan;
|
||||
|
||||
vulkan2D_.DeviceRestore(vulkan_);
|
||||
vulkan2D_->DeviceRestore(vulkan_);
|
||||
InitDeviceObjects();
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "GPU/GPUInterface.h"
|
||||
#include "GPU/Common/GPUDebugInterface.h"
|
||||
#include "GPU/Vulkan/VulkanUtil.h"
|
||||
#include "GPU/Vulkan/DepalettizeShaderVulkan.h"
|
||||
|
||||
// TODO: Remove?
|
||||
enum VulkanFBOColorDepth {
|
||||
@@ -44,6 +45,8 @@ R"( vec2 texelDelta;
|
||||
vec4 time;
|
||||
)";
|
||||
|
||||
class VulkanPushBuffer;
|
||||
|
||||
class FramebufferManagerVulkan : public FramebufferManagerCommon {
|
||||
public:
|
||||
FramebufferManagerVulkan(Draw::DrawContext *draw, VulkanContext *vulkan);
|
||||
@@ -52,6 +55,8 @@ public:
|
||||
void SetTextureCache(TextureCacheVulkan *tc);
|
||||
void SetShaderManager(ShaderManagerVulkan *sm);
|
||||
void SetDrawEngine(DrawEngineVulkan *td);
|
||||
void SetVulkan2D(Vulkan2D *vk2d) { vulkan2D_ = vk2d; }
|
||||
void SetPushBuffer(VulkanPushBuffer *push) { push_ = push; }
|
||||
|
||||
// x,y,w,h are relative to destW, destH which fill out the target completely.
|
||||
void DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags) override;
|
||||
@@ -105,28 +110,21 @@ private:
|
||||
// Used to keep track of command buffers here but have moved all that into Thin3D.
|
||||
|
||||
// Used by DrawPixels
|
||||
VulkanTexture *drawPixelsTex_;
|
||||
GEBufferFormat drawPixelsTexFormat_;
|
||||
|
||||
u8 *convBuf_;
|
||||
u32 convBufSize_;
|
||||
VulkanTexture *drawPixelsTex_ = nullptr;
|
||||
GEBufferFormat drawPixelsTexFormat_ = GE_FORMAT_INVALID;
|
||||
u8 *convBuf_ = nullptr;
|
||||
u32 convBufSize_ = 0;
|
||||
|
||||
TextureCacheVulkan *textureCacheVulkan_;
|
||||
ShaderManagerVulkan *shaderManagerVulkan_;
|
||||
DrawEngineVulkan *drawEngineVulkan_;
|
||||
VulkanPushBuffer *push_;
|
||||
|
||||
DepalShaderCacheVulkan depalVulkan_;
|
||||
enum {
|
||||
MAX_COMMAND_BUFFERS = 32,
|
||||
};
|
||||
|
||||
// Commandbuffers are handled internally in thin3d, one for each framebuffer pass.
|
||||
struct FrameData {
|
||||
VulkanPushBuffer *push_;
|
||||
};
|
||||
|
||||
FrameData frameData_[VulkanContext::MAX_INFLIGHT_FRAMES];
|
||||
int curFrame_;
|
||||
|
||||
// This gets copied to the current frame's push buffer as needed.
|
||||
PostShaderUniforms postUniforms_;
|
||||
|
||||
@@ -148,5 +146,5 @@ private:
|
||||
VkImageView overrideImageView_ = VK_NULL_HANDLE;
|
||||
|
||||
// Simple 2D drawing engine.
|
||||
Vulkan2D vulkan2D_;
|
||||
Vulkan2D *vulkan2D_;
|
||||
};
|
||||
@@ -76,7 +76,9 @@ static const VulkanCommandTableEntry commandTable[] = {
|
||||
GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
|
||||
: GPUCommon(gfxCtx, draw),
|
||||
vulkan_((VulkanContext *)gfxCtx->GetAPIContext()),
|
||||
drawEngine_(vulkan_, draw) {
|
||||
drawEngine_(vulkan_, draw),
|
||||
depalShaderCache_(draw, vulkan_),
|
||||
vulkan2D_(vulkan_) {
|
||||
UpdateVsyncInterval(true);
|
||||
CheckGPUFeatures();
|
||||
|
||||
@@ -97,10 +99,14 @@ GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
|
||||
framebufferManagerVulkan_->SetTextureCache(textureCacheVulkan_);
|
||||
framebufferManagerVulkan_->SetDrawEngine(&drawEngine_);
|
||||
framebufferManagerVulkan_->SetShaderManager(shaderManagerVulkan_);
|
||||
textureCacheVulkan_->SetFramebufferManager(framebufferManagerVulkan_);
|
||||
framebufferManagerVulkan_->SetVulkan2D(&vulkan2D_);
|
||||
textureCacheVulkan_->SetDepalShaderCache(&depalShaderCache_);
|
||||
textureCacheVulkan_->SetFramebufferManager(framebufferManagerVulkan_);
|
||||
textureCacheVulkan_->SetShaderManager(shaderManagerVulkan_);
|
||||
textureCacheVulkan_->SetDrawEngine(&drawEngine_);
|
||||
textureCacheVulkan_->SetVulkan2D(&vulkan2D_);
|
||||
|
||||
InitDeviceObjects();
|
||||
|
||||
// Sanity check gstate
|
||||
if ((int *)&gstate.transferstart - (int *)&gstate != 0xEA) {
|
||||
@@ -155,7 +161,9 @@ GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
|
||||
}
|
||||
|
||||
GPU_Vulkan::~GPU_Vulkan() {
|
||||
DestroyDeviceObjects();
|
||||
framebufferManagerVulkan_->DestroyAllFBOs();
|
||||
vulkan2D_.Shutdown();
|
||||
depalShaderCache_.Clear();
|
||||
delete textureCacheVulkan_;
|
||||
delete pipelineManager_;
|
||||
@@ -209,9 +217,19 @@ void GPU_Vulkan::BeginHostFrame() {
|
||||
resized_ = false;
|
||||
|
||||
textureCacheVulkan_->StartFrame();
|
||||
depalShaderCache_.Decimate();
|
||||
|
||||
|
||||
FrameData &frame = frameData_[curFrame_];
|
||||
|
||||
frame.push_->Reset();
|
||||
frame.push_->Begin(vulkan_);
|
||||
|
||||
framebufferManagerVulkan_->BeginFrameVulkan();
|
||||
framebufferManagerVulkan_->SetPushBuffer(frameData_[curFrame_].push_);
|
||||
depalShaderCache_.SetPushBuffer(frameData_[curFrame_].push_);
|
||||
textureCacheVulkan_->SetPushBuffer(frameData_[curFrame_].push_);
|
||||
|
||||
vulkan2D_.BeginFrame();
|
||||
|
||||
shaderManagerVulkan_->DirtyShader();
|
||||
gstate_c.Dirty(DIRTY_ALL);
|
||||
@@ -226,6 +244,16 @@ void GPU_Vulkan::BeginHostFrame() {
|
||||
}
|
||||
|
||||
void GPU_Vulkan::EndHostFrame() {
|
||||
FrameData &frame = frameData_[curFrame_];
|
||||
frame.push_->End();
|
||||
|
||||
vulkan2D_.EndFrame();
|
||||
|
||||
curFrame_++;
|
||||
if (curFrame_ >= vulkan_->GetInflightFrames()) {
|
||||
curFrame_ = 0;
|
||||
}
|
||||
|
||||
drawEngine_.EndFrame();
|
||||
framebufferManagerVulkan_->EndFrame();
|
||||
textureCacheVulkan_->EndFrame();
|
||||
@@ -769,7 +797,26 @@ void GPU_Vulkan::FastLoadBoneMatrix(u32 target) {
|
||||
gstate.FastLoadBoneMatrix(target);
|
||||
}
|
||||
|
||||
void GPU_Vulkan::InitDeviceObjects() {
|
||||
// Initialize framedata
|
||||
for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) {
|
||||
frameData_[i].push_ = new VulkanPushBuffer(vulkan_, 64 * 1024);
|
||||
}
|
||||
}
|
||||
|
||||
void GPU_Vulkan::DestroyDeviceObjects() {
|
||||
for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) {
|
||||
if (frameData_[i].push_) {
|
||||
frameData_[i].push_->Destroy(vulkan_);
|
||||
delete frameData_[i].push_;
|
||||
frameData_[i].push_ = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GPU_Vulkan::DeviceLost() {
|
||||
DestroyDeviceObjects();
|
||||
|
||||
framebufferManagerVulkan_->DeviceLost();
|
||||
drawEngine_.DeviceLost();
|
||||
pipelineManager_->DeviceLost();
|
||||
|
||||
@@ -101,6 +101,10 @@ private:
|
||||
void ReinitializeInternal() override;
|
||||
inline void UpdateVsyncInterval(bool force);
|
||||
void UpdateCmdInfo();
|
||||
|
||||
void InitDeviceObjects();
|
||||
void DestroyDeviceObjects();
|
||||
|
||||
static CommandInfo cmdInfo_[256];
|
||||
|
||||
VulkanContext *vulkan_;
|
||||
@@ -121,4 +125,14 @@ private:
|
||||
|
||||
std::string reportingPrimaryInfo_;
|
||||
std::string reportingFullInfo_;
|
||||
|
||||
// Simple 2D drawing engine.
|
||||
Vulkan2D vulkan2D_;
|
||||
|
||||
struct FrameData {
|
||||
VulkanPushBuffer *push_;
|
||||
};
|
||||
|
||||
FrameData frameData_[VulkanContext::MAX_INFLIGHT_FRAMES]{};
|
||||
int curFrame_ = 0;
|
||||
};
|
||||
@@ -152,6 +152,11 @@ void TextureCacheVulkan::SetFramebufferManager(FramebufferManagerVulkan *fbManag
|
||||
framebufferManager_ = fbManager;
|
||||
}
|
||||
|
||||
void TextureCacheVulkan::SetVulkan2D(Vulkan2D *vk2d) {
|
||||
vulkan2D_ = vk2d;
|
||||
depalShaderCache_->SetVulkan2D(vk2d);
|
||||
}
|
||||
|
||||
void TextureCacheVulkan::DeviceLost() {
|
||||
Clear(true);
|
||||
|
||||
@@ -269,6 +274,8 @@ void TextureCacheVulkan::SetFramebufferSamplingParams(u16 bufferWidth, u16 buffe
|
||||
|
||||
void TextureCacheVulkan::StartFrame() {
|
||||
InvalidateLastTexture();
|
||||
depalShaderCache_->Decimate();
|
||||
|
||||
timesInvalidatedAllThisFrame_ = 0;
|
||||
texelsScaledThisFrame_ = 0;
|
||||
|
||||
@@ -343,42 +350,24 @@ void TextureCacheVulkan::Unbind() {
|
||||
}
|
||||
|
||||
void TextureCacheVulkan::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuffer *framebuffer) {
|
||||
DepalShaderVulkan *depal = nullptr;
|
||||
DepalShaderVulkan *depalShader = nullptr;
|
||||
const GEPaletteFormat clutFormat = gstate.getClutPaletteFormat();
|
||||
if ((entry->status & TexCacheEntry::STATUS_DEPALETTIZE) && !g_Config.bDisableSlowFramebufEffects) {
|
||||
// depal = depalShaderCache_->GetDepalettizeShader(clutFormat, framebuffer->drawnFormat);
|
||||
depalShader = depalShaderCache_->GetDepalettizeShader(clutFormat, framebuffer->drawnFormat);
|
||||
}
|
||||
if (depal) {
|
||||
// VulkanTexture *clutTexture = depalShaderCache_->GetClutTexture(clutFormat, clutHash_, clutBuf_);
|
||||
// VulkanFBO *depalFBO = framebufferManager_->GetTempFBO(framebuffer->renderWidth, framebuffer->renderHeight, VK_FBO_8888);
|
||||
if (depalShader) {
|
||||
depalShaderCache_->SetPushBuffer(drawEngine_->GetPushBufferForTextureData());
|
||||
VulkanTexture *clutTexture = depalShaderCache_->GetClutTexture(clutFormat, clutHash_, clutBuf_);
|
||||
|
||||
//depalFBO->BeginPass(cmd);
|
||||
Draw::Framebuffer *depalFBO = framebufferManager_->GetTempFBO(
|
||||
framebuffer->renderWidth, framebuffer->renderHeight, Draw::FBO_8888);
|
||||
draw_->BindFramebufferAsRenderTarget(depalFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE });
|
||||
|
||||
struct Pos {
|
||||
Pos(float x_, float y_, float z_) : x(x_), y(y_), z(z_) {
|
||||
}
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
};
|
||||
struct UV {
|
||||
UV(float u_, float v_) : u(u_), v(v_) {
|
||||
}
|
||||
float u;
|
||||
float v;
|
||||
};
|
||||
|
||||
Pos pos[4] = {
|
||||
{ -1, -1, -1 },
|
||||
{ 1, -1, -1 },
|
||||
{ 1, 1, -1 },
|
||||
{ -1, 1, -1 },
|
||||
};
|
||||
UV uv[4] = {
|
||||
{ 0, 0 },
|
||||
{ 1, 0 },
|
||||
{ 1, 1 },
|
||||
{ 0, 1 },
|
||||
Vulkan2D::Vertex verts[4] = {
|
||||
{ -1, -1, -1, 0, 0 },
|
||||
{ 1, -1, -1, 1, 0 },
|
||||
{ 1, 1, -1, 1, 1 },
|
||||
{ -1, 1, -1, 0, 1 },
|
||||
};
|
||||
static const int indices[4] = { 0, 1, 3, 2 };
|
||||
|
||||
@@ -400,28 +389,32 @@ void TextureCacheVulkan::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFr
|
||||
const float top = v1 * invHalfHeight - 1.0f;
|
||||
const float bottom = v2 * invHalfHeight - 1.0f;
|
||||
// Points are: BL, BR, TR, TL.
|
||||
pos[0] = Pos(left, bottom, -1.0f);
|
||||
pos[1] = Pos(right, bottom, -1.0f);
|
||||
pos[2] = Pos(right, top, -1.0f);
|
||||
pos[3] = Pos(left, top, -1.0f);
|
||||
verts[0].x = left;
|
||||
verts[0].y = bottom;
|
||||
verts[1].x = right;
|
||||
verts[1].y = bottom;
|
||||
verts[2].x = right;
|
||||
verts[2].y = top;
|
||||
verts[3].x = left;
|
||||
verts[3].y = top;
|
||||
|
||||
// And also the UVs, same order.
|
||||
const float uvleft = u1 * invWidth;
|
||||
const float uvright = u2 * invWidth;
|
||||
const float uvtop = v1 * invHeight;
|
||||
const float uvbottom = v2 * invHeight;
|
||||
uv[0] = UV(uvleft, uvbottom);
|
||||
uv[1] = UV(uvright, uvbottom);
|
||||
uv[2] = UV(uvright, uvtop);
|
||||
uv[3] = UV(uvleft, uvtop);
|
||||
verts[0].u = uvleft;
|
||||
verts[0].v = uvbottom;
|
||||
verts[1].u = uvright;
|
||||
verts[1].v = uvbottom;
|
||||
verts[2].u = uvright;
|
||||
verts[2].v = uvtop;
|
||||
verts[3].u = uvleft;
|
||||
verts[3].v = uvtop;
|
||||
}
|
||||
|
||||
shaderManagerVulkan_->DirtyLastShader();
|
||||
|
||||
//depalFBO->EndPass(cmd);
|
||||
//depalFBO->TransitionToTexture(cmd);
|
||||
//imageView = depalFBO->GetColorImageView();
|
||||
|
||||
const u32 bytesPerColor = clutFormat == GE_CMODE_32BIT_ABGR8888 ? sizeof(u32) : sizeof(u16);
|
||||
const u32 clutTotalColors = clutMaxBytes_ / bytesPerColor;
|
||||
|
||||
@@ -429,7 +422,8 @@ void TextureCacheVulkan::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFr
|
||||
gstate_c.SetTextureFullAlpha(alphaStatus == TexCacheEntry::STATUS_ALPHA_FULL);
|
||||
gstate_c.SetTextureSimpleAlpha(alphaStatus == TexCacheEntry::STATUS_ALPHA_SIMPLE);
|
||||
|
||||
// imageView_ = depalFbo->getImageView().
|
||||
draw_->BindFramebufferAsTexture(depalFBO, 0, Draw::FB_COLOR_BIT, 0);
|
||||
imageView_ = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE_IMAGEVIEW);
|
||||
} else {
|
||||
entry->status &= ~TexCacheEntry::STATUS_DEPALETTIZE;
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ private:
|
||||
DenseHashMap<SamplerCacheKey, VkSampler, (VkSampler)VK_NULL_HANDLE> cache_;
|
||||
};
|
||||
|
||||
class Vulkan2D;
|
||||
|
||||
class TextureCacheVulkan : public TextureCacheCommon {
|
||||
public:
|
||||
@@ -83,6 +84,10 @@ public:
|
||||
void SetDrawEngine(DrawEngineVulkan *td) {
|
||||
drawEngine_ = td;
|
||||
}
|
||||
void SetVulkan2D(Vulkan2D *vk2d);
|
||||
void SetPushBuffer(VulkanPushBuffer *push) {
|
||||
push_ = push;
|
||||
}
|
||||
|
||||
void ForgetLastTexture() override {
|
||||
lastBoundTexture = nullptr;
|
||||
@@ -119,6 +124,7 @@ private:
|
||||
|
||||
VulkanContext *vulkan_;
|
||||
VulkanDeviceAllocator *allocator_;
|
||||
VulkanPushBuffer *push_;
|
||||
|
||||
SamplerCache samplerCache_;
|
||||
|
||||
@@ -134,6 +140,7 @@ private:
|
||||
DepalShaderCacheVulkan *depalShaderCache_;
|
||||
ShaderManagerVulkan *shaderManagerVulkan_;
|
||||
DrawEngineVulkan *drawEngine_;
|
||||
Vulkan2D *vulkan2D_;
|
||||
|
||||
// Bound state to emulate an API similar to the others
|
||||
VkImageView imageView_ = VK_NULL_HANDLE;
|
||||
|
||||
@@ -36,6 +36,7 @@ void Vulkan2D::DestroyDeviceObjects() {
|
||||
for (int i = 0; i < vulkan_->GetInflightFrames(); i++) {
|
||||
if (frameData_[i].descPool != VK_NULL_HANDLE) {
|
||||
vulkan_->Delete().QueueDeleteDescriptorPool(frameData_[i].descPool);
|
||||
frameData_[i].descPool = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
for (auto it : pipelines_) {
|
||||
@@ -52,9 +53,16 @@ void Vulkan2D::DestroyDeviceObjects() {
|
||||
vkDestroyPipelineLayout(device, pipelineLayout_, nullptr);
|
||||
pipelineLayout_ = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
// pipelineBasicTex_ and pipelineBasicTex_ come from vulkan2D_.
|
||||
if (pipelineCache_ != VK_NULL_HANDLE) {
|
||||
vulkan_->Delete().QueueDeletePipelineCache(pipelineCache_);
|
||||
pipelineCache_ = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
void Vulkan2D::InitDeviceObjects() {
|
||||
pipelineCache_ = vulkan_->CreatePipelineCache();
|
||||
// All resources we need for PSP drawing. Usually only bindings 0 and 2-4 are populated.
|
||||
VkDescriptorSetLayoutBinding bindings[2] = {};
|
||||
bindings[0].descriptorCount = 1;
|
||||
@@ -188,7 +196,7 @@ VkDescriptorSet Vulkan2D::GetDescriptorSet(VkImageView tex1, VkSampler sampler1,
|
||||
return desc;
|
||||
}
|
||||
|
||||
VkPipeline Vulkan2D::GetPipeline(VkPipelineCache cache, VkRenderPass rp, VkShaderModule vs, VkShaderModule fs) {
|
||||
VkPipeline Vulkan2D::GetPipeline(VkRenderPass rp, VkShaderModule vs, VkShaderModule fs) {
|
||||
PipelineKey key;
|
||||
key.vs = vs;
|
||||
key.fs = fs;
|
||||
@@ -298,7 +306,7 @@ VkPipeline Vulkan2D::GetPipeline(VkPipelineCache cache, VkRenderPass rp, VkShade
|
||||
pipe.subpass = 0;
|
||||
|
||||
VkPipeline pipeline;
|
||||
VkResult result = vkCreateGraphicsPipelines(vulkan_->GetDevice(), cache, 1, &pipe, nullptr, &pipeline);
|
||||
VkResult result = vkCreateGraphicsPipelines(vulkan_->GetDevice(), pipelineCache_, 1, &pipe, nullptr, &pipeline);
|
||||
if (result == VK_SUCCESS) {
|
||||
pipelines_[key] = pipeline;
|
||||
return pipeline;
|
||||
|
||||
@@ -56,7 +56,7 @@ public:
|
||||
void DeviceRestore(VulkanContext *vulkan);
|
||||
void Shutdown();
|
||||
|
||||
VkPipeline GetPipeline(VkPipelineCache cache, VkRenderPass rp, VkShaderModule vs, VkShaderModule fs);
|
||||
VkPipeline GetPipeline(VkRenderPass rp, VkShaderModule vs, VkShaderModule fs);
|
||||
VkPipelineLayout GetPipelineLayout() const { return pipelineLayout_; }
|
||||
void BeginFrame();
|
||||
void EndFrame();
|
||||
@@ -72,9 +72,10 @@ private:
|
||||
void InitDeviceObjects();
|
||||
void DestroyDeviceObjects();
|
||||
|
||||
VulkanContext *vulkan_;
|
||||
VkDescriptorSetLayout descriptorSetLayout_;
|
||||
VkPipelineLayout pipelineLayout_;
|
||||
VulkanContext *vulkan_ = nullptr;
|
||||
VkDescriptorSetLayout descriptorSetLayout_ = VK_NULL_HANDLE;
|
||||
VkPipelineLayout pipelineLayout_ = VK_NULL_HANDLE;
|
||||
VkPipelineCache pipelineCache_ = VK_NULL_HANDLE;
|
||||
|
||||
// Yes, another one...
|
||||
struct DescriptorSetKey {
|
||||
|
||||
Reference in new issue
Block a user