CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/GPU/Common/TextureShaderCommon.cpp
Views: 1401
// Copyright (c) 2014- PPSSPP Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official git repository and contact information can be found at15// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.1617#include <map>1819#include "Common/Log.h"20#include "Common/StringUtils.h"21#include "Common/GPU/Shader.h"22#include "Common/GPU/ShaderWriter.h"23#include "Common/Data/Convert/ColorConv.h"24#include "GPU/Common/Draw2D.h"25#include "GPU/Common/DrawEngineCommon.h"26#include "GPU/Common/TextureCacheCommon.h"27#include "GPU/Common/TextureShaderCommon.h"28#include "GPU/Common/DepalettizeShaderCommon.h"2930static const VaryingDef varyings[1] = {31{ "vec2", "v_texcoord", Draw::SEM_TEXCOORD0, 0, "highp" },32};3334static const SamplerDef samplers[2] = {35{ 0, "tex", SamplerFlags::ARRAY_ON_VULKAN },36{ 1, "pal" },37};3839TextureShaderCache::TextureShaderCache(Draw::DrawContext *draw, Draw2D *draw2D) : draw_(draw), draw2D_(draw2D) { }4041TextureShaderCache::~TextureShaderCache() {42DeviceLost();43}4445void TextureShaderCache::DeviceRestore(Draw::DrawContext *draw) {46draw_ = draw;47}4849void TextureShaderCache::DeviceLost() {50Clear();51draw_ = nullptr;52}5354ClutTexture TextureShaderCache::GetClutTexture(GEPaletteFormat clutFormat, const u32 clutHash, const u32 *rawClut) {55// Simplistic, but works well enough.56u32 clutId = clutHash ^ (uint32_t)clutFormat;5758auto oldtex = texCache_.find(clutId);59if (oldtex != texCache_.end()) {60oldtex->second->lastFrame = gpuStats.numFlips;61return *oldtex->second;62}6364int maxClutEntries = clutFormat == GE_CMODE_32BIT_ABGR8888 ? 256 : 512;6566ClutTexture *tex = new ClutTexture();6768Draw::TextureDesc desc{};69desc.width = 512; // We always use 512-sized textures here for simplicity, though the most common is that only up to 256 entries are used.70desc.height = 1;71desc.depth = 1;72desc.mipLevels = 1;73desc.tag = "clut";74desc.type = Draw::TextureType::LINEAR2D; // TODO: Try LINEAR1D?75desc.format = Draw::DataFormat::R8G8B8A8_UNORM; // TODO: Also support an BGR format. We won't bother with the 16-bit formats here.7677uint8_t convTemp[2048]{};7879switch (clutFormat) {80case GEPaletteFormat::GE_CMODE_32BIT_ABGR8888:81desc.initData.push_back((const uint8_t *)rawClut);82break;83case GEPaletteFormat::GE_CMODE_16BIT_BGR5650:84ConvertRGB565ToRGBA8888((u32 *)convTemp, (const u16 *)rawClut, maxClutEntries);85desc.initData.push_back(convTemp);86break;87case GEPaletteFormat::GE_CMODE_16BIT_ABGR5551:88ConvertRGBA5551ToRGBA8888((u32 *)convTemp, (const u16 *)rawClut, maxClutEntries);89desc.initData.push_back(convTemp);90break;91case GEPaletteFormat::GE_CMODE_16BIT_ABGR4444:92ConvertRGBA4444ToRGBA8888((u32 *)convTemp, (const u16 *)rawClut, maxClutEntries);93desc.initData.push_back(convTemp);94break;95}969798for (int i = 0; i < 3; i++) {99tex->rampLengths[i] = 0;100tex->rampStarts[i] = 0;101}102// Quick check for how many continuously growing entries we have at the start.103// Bilinearly filtering CLUTs only really makes sense for this kind of ramp.104int i = 0;105for (int j = 0; j < ClutTexture::MAX_RAMPS; j++) {106tex->rampStarts[j] = i;107int lastR = 0;108int lastG = 0;109int lastB = 0;110int lastA = 0;111for (; i < maxClutEntries; i++) {112int r = desc.initData[0][i * 4];113int g = desc.initData[0][i * 4 + 1];114int b = desc.initData[0][i * 4 + 2];115int a = desc.initData[0][i * 4 + 3];116if (r < lastR || g < lastG || b < lastB || a < lastA) {117lastR = r; lastG = g; lastB = b; lastA = a;118break;119} else {120lastR = r;121lastG = g;122lastB = b;123lastA = a;124}125}126tex->rampLengths[j] = i - tex->rampStarts[j];127if (i >= maxClutEntries) {128break;129}130}131132tex->texture = draw_->CreateTexture(desc);133tex->lastFrame = gpuStats.numFlips;134135texCache_[clutId] = tex;136return *tex;137}138139void TextureShaderCache::Clear() {140for (auto shader = depalCache_.begin(); shader != depalCache_.end(); ++shader) {141if (shader->second->pipeline) {142shader->second->pipeline->Release();143}144delete shader->second;145}146depalCache_.clear();147for (auto tex = texCache_.begin(); tex != texCache_.end(); ++tex) {148tex->second->texture->Release();149delete tex->second;150}151texCache_.clear();152if (nearestSampler_) {153nearestSampler_->Release();154nearestSampler_ = nullptr;155}156if (linearSampler_) {157linearSampler_->Release();158linearSampler_ = nullptr;159}160}161162Draw::SamplerState *TextureShaderCache::GetSampler(bool linearFilter) {163if (linearFilter) {164if (!linearSampler_) {165Draw::SamplerStateDesc desc{};166desc.magFilter = Draw::TextureFilter::LINEAR;167desc.minFilter = Draw::TextureFilter::LINEAR;168desc.wrapU = Draw::TextureAddressMode::CLAMP_TO_EDGE;169desc.wrapV = Draw::TextureAddressMode::CLAMP_TO_EDGE;170desc.wrapW = Draw::TextureAddressMode::CLAMP_TO_EDGE;171linearSampler_ = draw_->CreateSamplerState(desc);172}173return linearSampler_;174} else {175if (!nearestSampler_) {176Draw::SamplerStateDesc desc{};177desc.wrapU = Draw::TextureAddressMode::CLAMP_TO_EDGE;178desc.wrapV = Draw::TextureAddressMode::CLAMP_TO_EDGE;179desc.wrapW = Draw::TextureAddressMode::CLAMP_TO_EDGE;180nearestSampler_ = draw_->CreateSamplerState(desc);181}182return nearestSampler_;183}184}185186void TextureShaderCache::Decimate() {187for (auto tex = texCache_.begin(); tex != texCache_.end(); ) {188if (tex->second->lastFrame + DEPAL_TEXTURE_OLD_AGE < gpuStats.numFlips) {189tex->second->texture->Release();190delete tex->second;191texCache_.erase(tex++);192} else {193++tex;194}195}196}197198Draw2DPipeline *TextureShaderCache::GetDepalettizeShader(uint32_t clutMode, GETextureFormat textureFormat, GEBufferFormat bufferFormat, bool smoothedDepal, u32 depthUpperBits) {199using namespace Draw;200201// Generate an ID for depal shaders.202u64 id = ((u64)depthUpperBits << 32) | (clutMode & 0xFFFFFF) | (textureFormat << 24) | (bufferFormat << 28);203204auto shader = depalCache_.find(id);205if (shader != depalCache_.end()) {206return shader->second;207}208209// TODO: Parse these out of clutMode some nice way, to become a bit more stateless.210DepalConfig config;211config.clutFormat = gstate.getClutPaletteFormat();212config.startPos = gstate.getClutIndexStartPos();213config.shift = gstate.getClutIndexShift();214config.mask = gstate.getClutIndexMask();215config.bufferFormat = bufferFormat;216config.textureFormat = textureFormat;217config.smoothedDepal = smoothedDepal;218config.depthUpperBits = depthUpperBits;219220Draw2DPipeline *ts = draw2D_->Create2DPipeline([=](ShaderWriter &writer) -> Draw2DPipelineInfo {221GenerateDepalFs(writer, config);222return Draw2DPipelineInfo{223"depal",224config.bufferFormat == GE_FORMAT_DEPTH16 ? RASTER_DEPTH : RASTER_COLOR,225RASTER_COLOR,226samplers227};228});229230depalCache_[id] = ts;231232return ts->pipeline ? ts : nullptr;233}234235std::vector<std::string> TextureShaderCache::DebugGetShaderIDs(DebugShaderType type) {236std::vector<std::string> ids;237for (auto &iter : depalCache_) {238ids.push_back(StringFromFormat("%08x", iter.first));239}240return ids;241}242243std::string TextureShaderCache::DebugGetShaderString(const std::string &idstr, DebugShaderType type, DebugShaderStringType stringType) {244uint32_t id = 0;245sscanf(idstr.c_str(), "%08x", &id);246auto iter = depalCache_.find(id);247if (iter == depalCache_.end())248return "";249switch (stringType) {250case SHADER_STRING_SHORT_DESC:251return idstr;252case SHADER_STRING_SOURCE_CODE:253return iter->second->code;254default:255return "";256}257}258259260