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/GLES/FragmentTestCacheGLES.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 "Common/GPU/thin3d.h"18#include "Common/GPU/OpenGL/GLDebugLog.h"19#include "Core/Config.h"20#include "GPU/GLES/FragmentTestCacheGLES.h"21#include "GPU/GPUState.h"22#include "GPU/Common/GPUStateUtils.h"23#include "GPU/Common/ShaderId.h"2425// These are small, let's give them plenty of frames.26static const int FRAGTEST_TEXTURE_OLD_AGE = 307;27static const int FRAGTEST_DECIMATION_INTERVAL = 113;2829FragmentTestCacheGLES::FragmentTestCacheGLES(Draw::DrawContext *draw) {30render_ = (GLRenderManager *)draw->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);31}3233FragmentTestCacheGLES::~FragmentTestCacheGLES() {34Clear();35}3637void FragmentTestCacheGLES::DeviceRestore(Draw::DrawContext *draw) {38render_ = (GLRenderManager *)draw->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);39}4041void FragmentTestCacheGLES::BindTestTexture(int slot) {42bool alphaNeedsTexture = gstate.isAlphaTestEnabled() && !IsAlphaTestAgainstZero() && !IsAlphaTestTriviallyTrue();43bool colorNeedsTexture = gstate.isColorTestEnabled() && !IsColorTestAgainstZero() && !IsColorTestTriviallyTrue();44if (!alphaNeedsTexture && !colorNeedsTexture) {45// Common case: testing against zero. Just skip it, faster not to bind anything.46return;47}4849const FragmentTestID id = GenerateTestID();50const auto cached = cache_.find(id);51if (cached != cache_.end()) {52cached->second.lastFrame = gpuStats.numFlips;53GLRTexture *tex = cached->second.texture;54if (tex == lastTexture_) {55// Already bound, hurray.56return;57}58render_->BindTexture(slot, tex);59lastTexture_ = tex;60return;61}6263const u8 rRef = (gstate.getColorTestRef() >> 0) & 0xFF;64const u8 rMask = (gstate.getColorTestMask() >> 0) & 0xFF;65const u8 gRef = (gstate.getColorTestRef() >> 8) & 0xFF;66const u8 gMask = (gstate.getColorTestMask() >> 8) & 0xFF;67const u8 bRef = (gstate.getColorTestRef() >> 16) & 0xFF;68const u8 bMask = (gstate.getColorTestMask() >> 16) & 0xFF;69const u8 aRef = gstate.getAlphaTestRef();70const u8 aMask = gstate.getAlphaTestMask();71const u8 refs[4] = {rRef, gRef, bRef, aRef};72const u8 masks[4] = {rMask, gMask, bMask, aMask};73const GEComparison funcs[4] = {gstate.getColorTestFunction(), gstate.getColorTestFunction(), gstate.getColorTestFunction(), gstate.getAlphaTestFunction()};74const bool valid[4] = {gstate.isColorTestEnabled(), gstate.isColorTestEnabled(), gstate.isColorTestEnabled(), gstate.isAlphaTestEnabled()};7576GLRTexture *tex = CreateTestTexture(funcs, refs, masks, valid);77lastTexture_ = tex;78render_->BindTexture(slot, tex);79// We only need to do this once for the texture.80render_->SetTextureSampler(slot, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_NEAREST, GL_NEAREST, 0.0f);81FragmentTestTexture item;82item.lastFrame = gpuStats.numFlips;83item.texture = tex;84cache_[id] = item;85}8687FragmentTestID FragmentTestCacheGLES::GenerateTestID() {88FragmentTestID id;89// Let's just keep it simple, it's all in here.90id.alpha = gstate.isAlphaTestEnabled() ? gstate.alphatest : 0;91if (gstate.isColorTestEnabled()) {92id.colorRefFunc = gstate.getColorTestFunction() | (gstate.getColorTestRef() << 8);93id.colorMask = gstate.getColorTestMask();94} else {95id.colorRefFunc = 0;96id.colorMask = 0;97}98return id;99}100101GLRTexture *FragmentTestCacheGLES::CreateTestTexture(const GEComparison funcs[4], const u8 refs[4], const u8 masks[4], const bool valid[4]) {102u8 *data = new u8[256 * 4];103// TODO: Might it be better to use GL_ALPHA for simple textures?104// TODO: Experiment with 4-bit/etc. textures.105106// Build the logic map.107for (int color = 0; color < 256; ++color) {108for (int i = 0; i < 4; ++i) {109bool res = true;110if (valid[i]) {111switch (funcs[i]) {112case GE_COMP_NEVER:113res = false;114break;115case GE_COMP_ALWAYS:116res = true;117break;118case GE_COMP_EQUAL:119res = (color & masks[i]) == (refs[i] & masks[i]);120break;121case GE_COMP_NOTEQUAL:122res = (color & masks[i]) != (refs[i] & masks[i]);123break;124case GE_COMP_LESS:125res = (color & masks[i]) < (refs[i] & masks[i]);126break;127case GE_COMP_LEQUAL:128res = (color & masks[i]) <= (refs[i] & masks[i]);129break;130case GE_COMP_GREATER:131res = (color & masks[i]) > (refs[i] & masks[i]);132break;133case GE_COMP_GEQUAL:134res = (color & masks[i]) >= (refs[i] & masks[i]);135break;136}137}138data[color * 4 + i] = res ? 0xFF : 0;139}140}141142GLRTexture *tex = render_->CreateTexture(GL_TEXTURE_2D, 256, 1, 1, 1);143render_->TextureImage(tex, 0, 256, 1, 1, Draw::DataFormat::R8G8B8A8_UNORM, data);144return tex;145}146147void FragmentTestCacheGLES::Clear(bool deleteThem) {148if (deleteThem) {149for (const auto &[_, v] : cache_) {150render_->DeleteTexture(v.texture);151}152}153cache_.clear();154lastTexture_ = nullptr;155}156157void FragmentTestCacheGLES::Decimate() {158if (--decimationCounter_ <= 0) {159for (auto tex = cache_.begin(); tex != cache_.end(); ) {160if (tex->second.lastFrame + FRAGTEST_TEXTURE_OLD_AGE < gpuStats.numFlips) {161render_->DeleteTexture(tex->second.texture);162cache_.erase(tex++);163} else {164++tex;165}166}167168decimationCounter_ = FRAGTEST_DECIMATION_INTERVAL;169}170171lastTexture_ = nullptr;172}173174175