CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/GPU/Common/TextureShaderCommon.cpp
Views: 1401
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 <map>
19
20
#include "Common/Log.h"
21
#include "Common/StringUtils.h"
22
#include "Common/GPU/Shader.h"
23
#include "Common/GPU/ShaderWriter.h"
24
#include "Common/Data/Convert/ColorConv.h"
25
#include "GPU/Common/Draw2D.h"
26
#include "GPU/Common/DrawEngineCommon.h"
27
#include "GPU/Common/TextureCacheCommon.h"
28
#include "GPU/Common/TextureShaderCommon.h"
29
#include "GPU/Common/DepalettizeShaderCommon.h"
30
31
static const VaryingDef varyings[1] = {
32
{ "vec2", "v_texcoord", Draw::SEM_TEXCOORD0, 0, "highp" },
33
};
34
35
static const SamplerDef samplers[2] = {
36
{ 0, "tex", SamplerFlags::ARRAY_ON_VULKAN },
37
{ 1, "pal" },
38
};
39
40
TextureShaderCache::TextureShaderCache(Draw::DrawContext *draw, Draw2D *draw2D) : draw_(draw), draw2D_(draw2D) { }
41
42
TextureShaderCache::~TextureShaderCache() {
43
DeviceLost();
44
}
45
46
void TextureShaderCache::DeviceRestore(Draw::DrawContext *draw) {
47
draw_ = draw;
48
}
49
50
void TextureShaderCache::DeviceLost() {
51
Clear();
52
draw_ = nullptr;
53
}
54
55
ClutTexture TextureShaderCache::GetClutTexture(GEPaletteFormat clutFormat, const u32 clutHash, const u32 *rawClut) {
56
// Simplistic, but works well enough.
57
u32 clutId = clutHash ^ (uint32_t)clutFormat;
58
59
auto oldtex = texCache_.find(clutId);
60
if (oldtex != texCache_.end()) {
61
oldtex->second->lastFrame = gpuStats.numFlips;
62
return *oldtex->second;
63
}
64
65
int maxClutEntries = clutFormat == GE_CMODE_32BIT_ABGR8888 ? 256 : 512;
66
67
ClutTexture *tex = new ClutTexture();
68
69
Draw::TextureDesc desc{};
70
desc.width = 512; // We always use 512-sized textures here for simplicity, though the most common is that only up to 256 entries are used.
71
desc.height = 1;
72
desc.depth = 1;
73
desc.mipLevels = 1;
74
desc.tag = "clut";
75
desc.type = Draw::TextureType::LINEAR2D; // TODO: Try LINEAR1D?
76
desc.format = Draw::DataFormat::R8G8B8A8_UNORM; // TODO: Also support an BGR format. We won't bother with the 16-bit formats here.
77
78
uint8_t convTemp[2048]{};
79
80
switch (clutFormat) {
81
case GEPaletteFormat::GE_CMODE_32BIT_ABGR8888:
82
desc.initData.push_back((const uint8_t *)rawClut);
83
break;
84
case GEPaletteFormat::GE_CMODE_16BIT_BGR5650:
85
ConvertRGB565ToRGBA8888((u32 *)convTemp, (const u16 *)rawClut, maxClutEntries);
86
desc.initData.push_back(convTemp);
87
break;
88
case GEPaletteFormat::GE_CMODE_16BIT_ABGR5551:
89
ConvertRGBA5551ToRGBA8888((u32 *)convTemp, (const u16 *)rawClut, maxClutEntries);
90
desc.initData.push_back(convTemp);
91
break;
92
case GEPaletteFormat::GE_CMODE_16BIT_ABGR4444:
93
ConvertRGBA4444ToRGBA8888((u32 *)convTemp, (const u16 *)rawClut, maxClutEntries);
94
desc.initData.push_back(convTemp);
95
break;
96
}
97
98
99
for (int i = 0; i < 3; i++) {
100
tex->rampLengths[i] = 0;
101
tex->rampStarts[i] = 0;
102
}
103
// Quick check for how many continuously growing entries we have at the start.
104
// Bilinearly filtering CLUTs only really makes sense for this kind of ramp.
105
int i = 0;
106
for (int j = 0; j < ClutTexture::MAX_RAMPS; j++) {
107
tex->rampStarts[j] = i;
108
int lastR = 0;
109
int lastG = 0;
110
int lastB = 0;
111
int lastA = 0;
112
for (; i < maxClutEntries; i++) {
113
int r = desc.initData[0][i * 4];
114
int g = desc.initData[0][i * 4 + 1];
115
int b = desc.initData[0][i * 4 + 2];
116
int a = desc.initData[0][i * 4 + 3];
117
if (r < lastR || g < lastG || b < lastB || a < lastA) {
118
lastR = r; lastG = g; lastB = b; lastA = a;
119
break;
120
} else {
121
lastR = r;
122
lastG = g;
123
lastB = b;
124
lastA = a;
125
}
126
}
127
tex->rampLengths[j] = i - tex->rampStarts[j];
128
if (i >= maxClutEntries) {
129
break;
130
}
131
}
132
133
tex->texture = draw_->CreateTexture(desc);
134
tex->lastFrame = gpuStats.numFlips;
135
136
texCache_[clutId] = tex;
137
return *tex;
138
}
139
140
void TextureShaderCache::Clear() {
141
for (auto shader = depalCache_.begin(); shader != depalCache_.end(); ++shader) {
142
if (shader->second->pipeline) {
143
shader->second->pipeline->Release();
144
}
145
delete shader->second;
146
}
147
depalCache_.clear();
148
for (auto tex = texCache_.begin(); tex != texCache_.end(); ++tex) {
149
tex->second->texture->Release();
150
delete tex->second;
151
}
152
texCache_.clear();
153
if (nearestSampler_) {
154
nearestSampler_->Release();
155
nearestSampler_ = nullptr;
156
}
157
if (linearSampler_) {
158
linearSampler_->Release();
159
linearSampler_ = nullptr;
160
}
161
}
162
163
Draw::SamplerState *TextureShaderCache::GetSampler(bool linearFilter) {
164
if (linearFilter) {
165
if (!linearSampler_) {
166
Draw::SamplerStateDesc desc{};
167
desc.magFilter = Draw::TextureFilter::LINEAR;
168
desc.minFilter = Draw::TextureFilter::LINEAR;
169
desc.wrapU = Draw::TextureAddressMode::CLAMP_TO_EDGE;
170
desc.wrapV = Draw::TextureAddressMode::CLAMP_TO_EDGE;
171
desc.wrapW = Draw::TextureAddressMode::CLAMP_TO_EDGE;
172
linearSampler_ = draw_->CreateSamplerState(desc);
173
}
174
return linearSampler_;
175
} else {
176
if (!nearestSampler_) {
177
Draw::SamplerStateDesc desc{};
178
desc.wrapU = Draw::TextureAddressMode::CLAMP_TO_EDGE;
179
desc.wrapV = Draw::TextureAddressMode::CLAMP_TO_EDGE;
180
desc.wrapW = Draw::TextureAddressMode::CLAMP_TO_EDGE;
181
nearestSampler_ = draw_->CreateSamplerState(desc);
182
}
183
return nearestSampler_;
184
}
185
}
186
187
void TextureShaderCache::Decimate() {
188
for (auto tex = texCache_.begin(); tex != texCache_.end(); ) {
189
if (tex->second->lastFrame + DEPAL_TEXTURE_OLD_AGE < gpuStats.numFlips) {
190
tex->second->texture->Release();
191
delete tex->second;
192
texCache_.erase(tex++);
193
} else {
194
++tex;
195
}
196
}
197
}
198
199
Draw2DPipeline *TextureShaderCache::GetDepalettizeShader(uint32_t clutMode, GETextureFormat textureFormat, GEBufferFormat bufferFormat, bool smoothedDepal, u32 depthUpperBits) {
200
using namespace Draw;
201
202
// Generate an ID for depal shaders.
203
u64 id = ((u64)depthUpperBits << 32) | (clutMode & 0xFFFFFF) | (textureFormat << 24) | (bufferFormat << 28);
204
205
auto shader = depalCache_.find(id);
206
if (shader != depalCache_.end()) {
207
return shader->second;
208
}
209
210
// TODO: Parse these out of clutMode some nice way, to become a bit more stateless.
211
DepalConfig config;
212
config.clutFormat = gstate.getClutPaletteFormat();
213
config.startPos = gstate.getClutIndexStartPos();
214
config.shift = gstate.getClutIndexShift();
215
config.mask = gstate.getClutIndexMask();
216
config.bufferFormat = bufferFormat;
217
config.textureFormat = textureFormat;
218
config.smoothedDepal = smoothedDepal;
219
config.depthUpperBits = depthUpperBits;
220
221
Draw2DPipeline *ts = draw2D_->Create2DPipeline([=](ShaderWriter &writer) -> Draw2DPipelineInfo {
222
GenerateDepalFs(writer, config);
223
return Draw2DPipelineInfo{
224
"depal",
225
config.bufferFormat == GE_FORMAT_DEPTH16 ? RASTER_DEPTH : RASTER_COLOR,
226
RASTER_COLOR,
227
samplers
228
};
229
});
230
231
depalCache_[id] = ts;
232
233
return ts->pipeline ? ts : nullptr;
234
}
235
236
std::vector<std::string> TextureShaderCache::DebugGetShaderIDs(DebugShaderType type) {
237
std::vector<std::string> ids;
238
for (auto &iter : depalCache_) {
239
ids.push_back(StringFromFormat("%08x", iter.first));
240
}
241
return ids;
242
}
243
244
std::string TextureShaderCache::DebugGetShaderString(const std::string &idstr, DebugShaderType type, DebugShaderStringType stringType) {
245
uint32_t id = 0;
246
sscanf(idstr.c_str(), "%08x", &id);
247
auto iter = depalCache_.find(id);
248
if (iter == depalCache_.end())
249
return "";
250
switch (stringType) {
251
case SHADER_STRING_SHORT_DESC:
252
return idstr;
253
case SHADER_STRING_SOURCE_CODE:
254
return iter->second->code;
255
default:
256
return "";
257
}
258
}
259
260