1 // Copyright (c) 2014- PPSSPP Project.
2
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0 or later versions.
6
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY{} without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License 2.0 for more details.
11
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
14
15 // Official git repository and contact information can be found at
16 // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18 #include "Common/Data/Convert/ColorConv.h"
19 #include "Common/GPU/Vulkan/VulkanImage.h"
20 #include "Common/GPU/Vulkan/VulkanMemory.h"
21 #include "Common/GPU/Vulkan/VulkanContext.h"
22 #include "GPU/ge_constants.h"
23 #include "GPU/GPUState.h"
24 #include "GPU/Common/DepalettizeShaderCommon.h"
25 #include "GPU/Vulkan/DepalettizeShaderVulkan.h"
26 #include "GPU/Vulkan/VulkanUtil.h"
27 #include "Common/GPU/Vulkan/VulkanImage.h"
28
29 static const char depal_vs[] = R"(#version 450
30 #extension GL_ARB_separate_shader_objects : enable
31 #extension GL_ARB_shading_language_420pack : enable
32 layout (location = 0) in vec3 a_position;
33 layout (location = 1) in vec2 a_texcoord0;
34 layout (location = 0) out vec2 v_texcoord0;
35 out gl_PerVertex { vec4 gl_Position; };
36 void main() {
37 v_texcoord0 = a_texcoord0;
38 gl_Position = vec4(a_position, 1.0);
39 }
40 )";
41
GetClutDestFormat(GEPaletteFormat format,VkComponentMapping * componentMapping)42 static VkFormat GetClutDestFormat(GEPaletteFormat format, VkComponentMapping *componentMapping) {
43 switch (format) {
44 case GE_CMODE_16BIT_ABGR4444:
45 *componentMapping = VULKAN_4444_SWIZZLE;
46 return VULKAN_4444_FORMAT;
47 case GE_CMODE_16BIT_ABGR5551:
48 *componentMapping = VULKAN_1555_SWIZZLE;
49 return VULKAN_1555_FORMAT;
50 case GE_CMODE_16BIT_BGR5650:
51 *componentMapping = VULKAN_565_SWIZZLE;
52 return VULKAN_565_FORMAT;
53 case GE_CMODE_32BIT_ABGR8888:
54 *componentMapping = VULKAN_8888_SWIZZLE;
55 return VULKAN_8888_FORMAT;
56 }
57 return VK_FORMAT_UNDEFINED;
58 }
59
DepalShaderCacheVulkan(Draw::DrawContext * draw,VulkanContext * vulkan)60 DepalShaderCacheVulkan::DepalShaderCacheVulkan(Draw::DrawContext *draw, VulkanContext *vulkan)
61 : draw_(draw), vulkan_(vulkan) {
62 DeviceRestore(draw, vulkan);
63 }
64
~DepalShaderCacheVulkan()65 DepalShaderCacheVulkan::~DepalShaderCacheVulkan() {
66 DeviceLost();
67 }
68
DeviceLost()69 void DepalShaderCacheVulkan::DeviceLost() {
70 Clear();
71 if (vshader_) {
72 vulkan2D_->PurgeVertexShader(vshader_);
73 vulkan_->Delete().QueueDeleteShaderModule(vshader_);
74 vshader_ = VK_NULL_HANDLE;
75 }
76 draw_ = nullptr;
77 vulkan_ = nullptr;
78 }
79
DeviceRestore(Draw::DrawContext * draw,VulkanContext * vulkan)80 void DepalShaderCacheVulkan::DeviceRestore(Draw::DrawContext *draw, VulkanContext *vulkan) {
81 draw_ = draw;
82 vulkan_ = vulkan;
83 std::string errors;
84 vshader_ = CompileShaderModule(vulkan_, VK_SHADER_STAGE_VERTEX_BIT, depal_vs, &errors);
85 _assert_(vshader_ != VK_NULL_HANDLE);
86 }
87
GetDepalettizeShader(uint32_t clutMode,GEBufferFormat pixelFormat)88 DepalShaderVulkan *DepalShaderCacheVulkan::GetDepalettizeShader(uint32_t clutMode, GEBufferFormat pixelFormat) {
89 u32 id = GenerateShaderID(clutMode, pixelFormat);
90
91 auto shader = cache_.find(id);
92 if (shader != cache_.end()) {
93 return shader->second;
94 }
95
96 VkRenderPass rp = (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::FRAMEBUFFER_RENDERPASS);
97
98 char *buffer = new char[2048];
99 GenerateDepalShader(buffer, pixelFormat, GLSL_VULKAN);
100
101 std::string error;
102 VkShaderModule fshader = CompileShaderModule(vulkan_, VK_SHADER_STAGE_FRAGMENT_BIT, buffer, &error);
103 if (fshader == VK_NULL_HANDLE) {
104 INFO_LOG(G3D, "Source:\n%s\n\n", buffer);
105 Crash();
106 delete[] buffer;
107 return nullptr;
108 }
109
110 VkPipeline pipeline = vulkan2D_->GetPipeline(rp, vshader_, fshader);
111 // Can delete the shader module now that the pipeline has been created.
112 // Maybe don't even need to queue it..
113 // "true" keeps the pipeline itself alive, forgetting the fshader.
114 vulkan2D_->PurgeFragmentShader(fshader, true);
115 vulkan_->Delete().QueueDeleteShaderModule(fshader);
116
117 DepalShaderVulkan *depal = new DepalShaderVulkan();
118 depal->pipeline = pipeline;
119 depal->code = buffer;
120 cache_[id] = depal;
121 return depal;
122 }
123
GetClutTexture(GEPaletteFormat clutFormat,u32 clutHash,u32 * rawClut,bool expandTo32bit)124 VulkanTexture *DepalShaderCacheVulkan::GetClutTexture(GEPaletteFormat clutFormat, u32 clutHash, u32 *rawClut, bool expandTo32bit) {
125 u32 clutId = GetClutID(clutFormat, clutHash);
126 auto oldtex = texCache_.find(clutId);
127 if (oldtex != texCache_.end()) {
128 oldtex->second->texture->Touch();
129 oldtex->second->lastFrame = gpuStats.numFlips;
130 return oldtex->second->texture;
131 }
132
133 VkComponentMapping componentMapping;
134 VkFormat destFormat = GetClutDestFormat(clutFormat, &componentMapping);
135
136 int texturePixels = clutFormat == GE_CMODE_32BIT_ABGR8888 ? 256 : 512;
137 int bpp = clutFormat == GE_CMODE_32BIT_ABGR8888 ? 4 : 2;
138 VkFormat dstFmt;
139 uint32_t *expanded = nullptr;
140 if (expandTo32bit && clutFormat != GE_CMODE_32BIT_ABGR8888) {
141 expanded = new uint32_t[texturePixels];
142 switch (clutFormat) {
143 case GE_CMODE_16BIT_ABGR4444:
144 ConvertRGBA4444ToRGBA8888(expanded, (const uint16_t *)rawClut, texturePixels);
145 break;
146 case GE_CMODE_16BIT_ABGR5551:
147 ConvertRGBA5551ToRGBA8888(expanded, (const uint16_t *)rawClut, texturePixels);
148 break;
149 case GE_CMODE_16BIT_BGR5650:
150 ConvertRGB565ToRGBA8888(expanded, (const uint16_t *)rawClut, texturePixels);
151 break;
152 default:
153 break;
154 }
155 rawClut = expanded;
156 dstFmt = VK_FORMAT_R8G8B8A8_UNORM;
157 bpp = 4;
158 componentMapping.r = VkComponentSwizzle::VK_COMPONENT_SWIZZLE_IDENTITY;
159 componentMapping.g = VkComponentSwizzle::VK_COMPONENT_SWIZZLE_IDENTITY;
160 componentMapping.b = VkComponentSwizzle::VK_COMPONENT_SWIZZLE_IDENTITY;
161 componentMapping.a = VkComponentSwizzle::VK_COMPONENT_SWIZZLE_IDENTITY;
162 } else {
163 dstFmt = GetClutDestFormat(clutFormat, &componentMapping);
164 }
165
166 VulkanTexture *vktex = new VulkanTexture(vulkan_);
167 vktex->SetTag("DepalClut");
168 VkCommandBuffer cmd = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::INIT_COMMANDBUFFER);
169 if (!vktex->CreateDirect(cmd, alloc_, texturePixels, 1, 1, destFormat,
170 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, &componentMapping)) {
171 ERROR_LOG(G3D, "Failed to create texture for CLUT");
172 return nullptr;
173 }
174
175 VkBuffer pushBuffer;
176 uint32_t pushOffset = push_->PushAligned(rawClut, 1024, 4, &pushBuffer);
177
178 vktex->UploadMip(cmd, 0, texturePixels, 1, pushBuffer, pushOffset, texturePixels);
179 vktex->EndCreate(cmd, false, VK_PIPELINE_STAGE_TRANSFER_BIT);
180
181 DepalTextureVulkan *tex = new DepalTextureVulkan();
182 tex->texture = vktex;
183 tex->lastFrame = gpuStats.numFlips;
184 texCache_[clutId] = tex;
185
186 if (expandTo32bit) {
187 delete[] expanded;
188 }
189
190 return tex->texture;
191 }
192
Clear()193 void DepalShaderCacheVulkan::Clear() {
194 for (auto shader = cache_.begin(); shader != cache_.end(); ++shader) {
195 // Don't need to destroy the pipelines, they're handled by Vulkan2D.
196 delete shader->second;
197 }
198 cache_.clear();
199
200 for (auto tex = texCache_.begin(); tex != texCache_.end(); ++tex) {
201 delete tex->second->texture;
202 delete tex->second;
203 }
204 texCache_.clear();
205 }
206
Decimate()207 void DepalShaderCacheVulkan::Decimate() {
208 // We don't bother decimating the generated shaders, there are never very many of them.
209 for (auto tex = texCache_.begin(); tex != texCache_.end(); ) {
210 if (tex->second->lastFrame + DEPAL_TEXTURE_OLD_AGE < gpuStats.numFlips) {
211 delete tex->second->texture;
212 delete tex->second;
213 texCache_.erase(tex++);
214 } else {
215 ++tex;
216 }
217 }
218 }
219