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