mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
OpenGL DrawContext texture handling cleanup, fixing some bugs.
This commit is contained in:
parent
1c33ac8dc1
commit
387ad7e4d6
4 changed files with 96 additions and 89 deletions
|
@ -82,7 +82,7 @@ public:
|
|||
}
|
||||
|
||||
protected:
|
||||
void SetViewport2D(int x, int y, int w, int h);
|
||||
void SetViewport2D(int x, int y, int w, int h) override;
|
||||
void DisableState() override;
|
||||
void ClearBuffer(bool keepState = false) override;
|
||||
void FlushBeforeCopy() override;
|
||||
|
|
|
@ -122,7 +122,7 @@ public:
|
|||
protected:
|
||||
void Bind2DShader() override;
|
||||
void BindPostShader(const PostShaderUniforms &uniforms) override;
|
||||
void SetViewport2D(int x, int y, int w, int h);
|
||||
void SetViewport2D(int x, int y, int w, int h) override;
|
||||
void DisableState() override {}
|
||||
void ClearBuffer(bool keepState = false) override;
|
||||
void FlushBeforeCopy() override;
|
||||
|
@ -135,7 +135,7 @@ protected:
|
|||
private:
|
||||
|
||||
// The returned texture does not need to be free'd, might be returned from a pool (currently single entry)
|
||||
void MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height);
|
||||
void MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height) override;
|
||||
void DoNotifyDraw();
|
||||
|
||||
VkCommandBuffer AllocFrameCommandBuffer();
|
||||
|
|
|
@ -111,8 +111,8 @@ enum class StencilOp {
|
|||
};
|
||||
|
||||
enum class TextureFilter : int {
|
||||
NEAREST,
|
||||
LINEAR,
|
||||
NEAREST = 0,
|
||||
LINEAR = 1,
|
||||
};
|
||||
|
||||
enum BufferUsageFlag : int {
|
||||
|
@ -273,7 +273,7 @@ enum {
|
|||
};
|
||||
|
||||
enum class TextureAddressMode {
|
||||
REPEAT,
|
||||
REPEAT = 0,
|
||||
REPEAT_MIRROR,
|
||||
CLAMP_TO_EDGE,
|
||||
CLAMP_TO_BORDER,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <stdio.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
|
||||
#include "base/logging.h"
|
||||
|
@ -77,7 +78,7 @@ static const unsigned short texWrapToGL[] = {
|
|||
#if !defined(USING_GLES2)
|
||||
GL_CLAMP_TO_BORDER,
|
||||
#else
|
||||
GL_REPEAT,
|
||||
GL_CLAMP_TO_EDGE,
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -193,30 +194,12 @@ public:
|
|||
|
||||
class OpenGLSamplerState : public SamplerState {
|
||||
public:
|
||||
// Old school. Should also support using a sampler object.
|
||||
|
||||
GLint wrapS;
|
||||
GLint wrapT;
|
||||
GLint wrapU;
|
||||
GLint wrapV;
|
||||
GLint wrapW;
|
||||
GLint magFilt;
|
||||
GLint minFilt;
|
||||
GLint mipMinFilt;
|
||||
|
||||
void Apply(bool hasMips, bool canWrap) {
|
||||
if (canWrap) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT);
|
||||
} else {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilt);
|
||||
if (hasMips) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mipMinFilt);
|
||||
} else {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilt);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class OpenGLDepthStencilState : public DepthStencilState {
|
||||
|
@ -437,6 +420,7 @@ private:
|
|||
};
|
||||
|
||||
class OpenGLFramebuffer;
|
||||
class OpenGLTexture;
|
||||
|
||||
class OpenGLContext : public DrawContext {
|
||||
public:
|
||||
|
@ -484,23 +468,12 @@ public:
|
|||
void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override;
|
||||
|
||||
void BindSamplerStates(int start, int count, SamplerState **states) override {
|
||||
if (samplerStates_.size() < (size_t)(start + count)) {
|
||||
samplerStates_.resize(start + count);
|
||||
if (boundSamplers_.size() < (size_t)(start + count)) {
|
||||
boundSamplers_.resize(start + count);
|
||||
}
|
||||
for (int i = 0; i < count; ++i) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
int index = i + start;
|
||||
OpenGLSamplerState *s = static_cast<OpenGLSamplerState *>(states[index]);
|
||||
|
||||
if (samplerStates_[index]) {
|
||||
samplerStates_[index]->Release();
|
||||
}
|
||||
samplerStates_[index] = s;
|
||||
samplerStates_[index]->AddRef();
|
||||
|
||||
// TODO: Ideally, get these from the texture and apply on the right stage?
|
||||
if (index == 0) {
|
||||
s->Apply(false, true);
|
||||
}
|
||||
boundSamplers_[index] = static_cast<OpenGLSamplerState *>(states[index]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -535,7 +508,7 @@ public:
|
|||
curIBufferOffset_ = offset;
|
||||
}
|
||||
|
||||
void UpdateDynamicUniformBuffer(const void *ub, size_t size);
|
||||
void UpdateDynamicUniformBuffer(const void *ub, size_t size) override;
|
||||
|
||||
// TODO: Add more sophisticated draws.
|
||||
void Draw(int vertexCount, int offset) override;
|
||||
|
@ -581,13 +554,16 @@ public:
|
|||
|
||||
void HandleEvent(Event ev) override {}
|
||||
|
||||
private:
|
||||
OpenGLFramebuffer *fbo_ext_create(const FramebufferDesc &desc);
|
||||
void fbo_bind_fb_target(bool read, GLuint name);
|
||||
GLenum fbo_get_fb_target(bool read, GLuint **cached);
|
||||
void fbo_unbind();
|
||||
void ApplySamplers();
|
||||
|
||||
private:
|
||||
std::vector<OpenGLSamplerState *> samplerStates_;
|
||||
std::vector<OpenGLSamplerState *> boundSamplers_;
|
||||
OpenGLTexture *boundTextures_[8]{};
|
||||
int maxTextures_ = 0;
|
||||
DeviceCaps caps_;
|
||||
|
||||
// Bound state
|
||||
|
@ -619,12 +595,7 @@ OpenGLContext::OpenGLContext() {
|
|||
}
|
||||
|
||||
OpenGLContext::~OpenGLContext() {
|
||||
for (OpenGLSamplerState *s : samplerStates_) {
|
||||
if (s) {
|
||||
s->Release();
|
||||
}
|
||||
}
|
||||
samplerStates_.clear();
|
||||
boundSamplers_.clear();
|
||||
}
|
||||
|
||||
InputLayout *OpenGLContext::CreateInputLayout(const InputLayoutDesc &desc) {
|
||||
|
@ -646,7 +617,9 @@ GLuint TypeToTarget(TextureType type) {
|
|||
case TextureType::ARRAY1D: return GL_TEXTURE_1D_ARRAY;
|
||||
#endif
|
||||
case TextureType::ARRAY2D: return GL_TEXTURE_2D_ARRAY;
|
||||
default: return GL_NONE;
|
||||
default:
|
||||
ELOG("Bad texture type %d", (int)type);
|
||||
return GL_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -659,44 +632,49 @@ public:
|
|||
OpenGLTexture(const TextureDesc &desc);
|
||||
~OpenGLTexture();
|
||||
|
||||
void AutoGenMipmaps();
|
||||
|
||||
bool HasMips() {
|
||||
bool HasMips() const {
|
||||
return mipLevels_ > 1 || generatedMips_;
|
||||
}
|
||||
bool CanWrap() {
|
||||
bool CanWrap() const {
|
||||
return canWrap_;
|
||||
}
|
||||
|
||||
TextureType GetType() const { return type_; }
|
||||
void Bind() {
|
||||
glBindTexture(target_, tex_);
|
||||
}
|
||||
|
||||
void AutoGenMipmaps();
|
||||
|
||||
private:
|
||||
void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data);
|
||||
|
||||
GLuint tex_;
|
||||
GLuint target_;
|
||||
GLuint tex_ = 0;
|
||||
GLuint target_ = 0;
|
||||
|
||||
DataFormat format_;
|
||||
TextureType type_;
|
||||
int mipLevels_;
|
||||
bool generatedMips_;
|
||||
bool canWrap_;
|
||||
};
|
||||
|
||||
OpenGLTexture::OpenGLTexture(const TextureDesc &desc) : tex_(0), target_(TypeToTarget(desc.type)), format_(desc.format), mipLevels_(desc.mipLevels) {
|
||||
OpenGLTexture::OpenGLTexture(const TextureDesc &desc) {
|
||||
generatedMips_ = false;
|
||||
canWrap_ = true;
|
||||
width_ = desc.width;
|
||||
height_ = desc.height;
|
||||
depth_ = desc.depth;
|
||||
canWrap_ = !isPowerOf2(width_) || !isPowerOf2(height_);
|
||||
|
||||
glGenTextures(1, &tex_);
|
||||
|
||||
format_ = desc.format;
|
||||
type_ = desc.type;
|
||||
target_ = TypeToTarget(desc.type);
|
||||
canWrap_ = isPowerOf2(width_) && isPowerOf2(height_);
|
||||
if (!desc.initData.size())
|
||||
return;
|
||||
|
||||
glActiveTexture(GL_TEXTURE0 + 0);
|
||||
glGenTextures(1, &tex_);
|
||||
glBindTexture(target_, tex_);
|
||||
|
||||
int level = 0;
|
||||
for (auto data : desc.initData) {
|
||||
SetImageData(0, 0, 0, width_, height_, depth_, level, 0, data);
|
||||
|
@ -704,19 +682,25 @@ OpenGLTexture::OpenGLTexture(const TextureDesc &desc) : tex_(0), target_(TypeToT
|
|||
height_ = (height_ + 1) / 2;
|
||||
level++;
|
||||
}
|
||||
mipLevels_ = level;
|
||||
|
||||
#ifdef USING_GLES2
|
||||
if (gl_extensions.GLES3) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level - 1);
|
||||
glTexParameteri(target_, GL_TEXTURE_MAX_LEVEL, level - 1);
|
||||
}
|
||||
#else
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level - 1);
|
||||
glTexParameteri(target_, GL_TEXTURE_MAX_LEVEL, level - 1);
|
||||
#endif
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, level > 1 ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(target_, GL_TEXTURE_MIN_FILTER, level > 1 ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
|
||||
glTexParameteri(target_, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
if (desc.initData.size() < desc.mipLevels)
|
||||
if (desc.initData.size() < desc.mipLevels) {
|
||||
ILOG("Generating mipmaps");
|
||||
AutoGenMipmaps();
|
||||
}
|
||||
|
||||
// Unbind.
|
||||
glBindTexture(target_, 0);
|
||||
}
|
||||
|
||||
OpenGLTexture::~OpenGLTexture() {
|
||||
|
@ -727,16 +711,10 @@ OpenGLTexture::~OpenGLTexture() {
|
|||
}
|
||||
}
|
||||
|
||||
Texture *OpenGLContext::CreateTexture(const TextureDesc &desc) {
|
||||
return new OpenGLTexture(desc);
|
||||
}
|
||||
|
||||
void OpenGLTexture::AutoGenMipmaps() {
|
||||
if (!generatedMips_) {
|
||||
Bind();
|
||||
glBindTexture(target_, tex_);
|
||||
glGenerateMipmap(target_);
|
||||
// TODO: Really, this should follow the sampler state.
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
|
||||
generatedMips_ = true;
|
||||
}
|
||||
}
|
||||
|
@ -775,13 +753,7 @@ void OpenGLTexture::SetImageData(int x, int y, int z, int width, int height, int
|
|||
ELOG("Thin3d GL: Unsupported texture format %d", (int)format_);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
GLenum err = glGetError();
|
||||
if (err) {
|
||||
ELOG("Thin3D GL: Error before loading texture: %08x", err);
|
||||
}*/
|
||||
|
||||
Bind();
|
||||
switch (target_) {
|
||||
case GL_TEXTURE_2D:
|
||||
glTexImage2D(GL_TEXTURE_2D, level, internalFormat, width_, height_, 0, format, type, data);
|
||||
|
@ -797,6 +769,10 @@ void OpenGLTexture::SetImageData(int x, int y, int z, int width, int height, int
|
|||
}
|
||||
}
|
||||
|
||||
Texture *OpenGLContext::CreateTexture(const TextureDesc &desc) {
|
||||
return new OpenGLTexture(desc);
|
||||
}
|
||||
|
||||
OpenGLInputLayout::~OpenGLInputLayout() {
|
||||
if (id_) {
|
||||
glDeleteVertexArrays(1, &id_);
|
||||
|
@ -862,8 +838,9 @@ BlendState *OpenGLContext::CreateBlendState(const BlendStateDesc &desc) {
|
|||
|
||||
SamplerState *OpenGLContext::CreateSamplerState(const SamplerStateDesc &desc) {
|
||||
OpenGLSamplerState *samps = new OpenGLSamplerState();
|
||||
samps->wrapS = texWrapToGL[(int)desc.wrapU];
|
||||
samps->wrapT = texWrapToGL[(int)desc.wrapV];
|
||||
samps->wrapU = texWrapToGL[(int)desc.wrapU];
|
||||
samps->wrapV = texWrapToGL[(int)desc.wrapV];
|
||||
samps->wrapW = texWrapToGL[(int)desc.wrapW];
|
||||
samps->magFilt = texFilterToGL[(int)desc.magFilter];
|
||||
samps->minFilt = texFilterToGL[(int)desc.minFilter];
|
||||
samps->mipMinFilt = texMipFilterToGL[(int)desc.minFilter][(int)desc.mipFilter];
|
||||
|
@ -990,22 +967,49 @@ Pipeline *OpenGLContext::CreateGraphicsPipeline(const PipelineDesc &desc) {
|
|||
}
|
||||
|
||||
void OpenGLContext::BindTextures(int start, int count, Texture **textures) {
|
||||
maxTextures_ = std::max(maxTextures_, start + count);
|
||||
for (int i = start; i < start + count; i++) {
|
||||
OpenGLTexture *glTex = static_cast<OpenGLTexture *>(textures[i]);
|
||||
glActiveTexture(GL_TEXTURE0 + i);
|
||||
if (!glTex) {
|
||||
boundTextures_[i] = 0;
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
continue;
|
||||
}
|
||||
glTex->Bind();
|
||||
|
||||
if ((int)samplerStates_.size() > i && samplerStates_[i]) {
|
||||
samplerStates_[i]->Apply(glTex->HasMips(), glTex->CanWrap());
|
||||
}
|
||||
boundTextures_[i] = glTex;
|
||||
}
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
|
||||
void OpenGLContext::ApplySamplers() {
|
||||
for (int i = 0; i < maxTextures_; i++) {
|
||||
if ((int)boundSamplers_.size() > i && boundSamplers_[i]) {
|
||||
const OpenGLSamplerState *samp = boundSamplers_[i];
|
||||
const OpenGLTexture *tex = boundTextures_[i];
|
||||
if (!tex)
|
||||
continue;
|
||||
if (tex->CanWrap()) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, samp->wrapU);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, samp->wrapV);
|
||||
#ifndef USING_GLES2
|
||||
if (tex->GetType() == TextureType::LINEAR3D)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, samp->wrapW);
|
||||
#endif
|
||||
} else {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, samp->magFilt);
|
||||
if (tex->HasMips()) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, samp->mipMinFilt);
|
||||
} else {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, samp->minFilt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ShaderModule *OpenGLContext::CreateShaderModule(ShaderStage stage, ShaderLanguage language, const uint8_t *data, size_t dataSize) {
|
||||
OpenGLShaderModule *shader = new OpenGLShaderModule(stage);
|
||||
|
@ -1112,6 +1116,7 @@ void OpenGLContext::UpdateDynamicUniformBuffer(const void *ub, size_t size) {
|
|||
void OpenGLContext::Draw(int vertexCount, int offset) {
|
||||
curVBuffers_[0]->Bind(curVBufferOffsets_[0]);
|
||||
curPipeline_->inputLayout->Apply();
|
||||
ApplySamplers();
|
||||
|
||||
glDrawArrays(curPipeline_->prim, offset, vertexCount);
|
||||
|
||||
|
@ -1121,6 +1126,7 @@ void OpenGLContext::Draw(int vertexCount, int offset) {
|
|||
void OpenGLContext::DrawIndexed(int vertexCount, int offset) {
|
||||
curVBuffers_[0]->Bind(curVBufferOffsets_[0]);
|
||||
curPipeline_->inputLayout->Apply();
|
||||
ApplySamplers();
|
||||
// Note: ibuf binding is stored in the VAO, so call this after binding the fmt.
|
||||
curIBuffer_->Bind(curIBufferOffset_);
|
||||
|
||||
|
@ -1131,6 +1137,7 @@ void OpenGLContext::DrawIndexed(int vertexCount, int offset) {
|
|||
|
||||
void OpenGLContext::DrawUP(const void *vdata, int vertexCount) {
|
||||
curPipeline_->inputLayout->Apply(vdata);
|
||||
ApplySamplers();
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
|
|
Loading…
Add table
Reference in a new issue