mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-09-27 23:06:34 +02:00
Merge pull request #9329 from hrydgard/shield-texture-fix
Assorted cleanup of GL texture handling. Fixes #9286
This commit is contained in:
@@ -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;
|
||||
|
||||
+69
-61
@@ -58,15 +58,7 @@ SoftGPU::SoftGPU(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
|
||||
: GPUCommon(gfxCtx, draw)
|
||||
{
|
||||
using namespace Draw;
|
||||
TextureDesc desc{};
|
||||
desc.type = TextureType::LINEAR2D;
|
||||
desc.format = DataFormat::R8G8B8A8_UNORM;
|
||||
desc.width = 480;
|
||||
desc.height = 272;
|
||||
desc.depth = 1;
|
||||
desc.mipLevels = 1;
|
||||
fbTex = draw_->CreateTexture(desc);
|
||||
|
||||
fbTex = nullptr;
|
||||
InputLayoutDesc inputDesc = {
|
||||
{
|
||||
{ sizeof(Vertex), false },
|
||||
@@ -124,9 +116,10 @@ SoftGPU::~SoftGPU() {
|
||||
texColor->Release();
|
||||
texColor = nullptr;
|
||||
|
||||
fbTex->Release();
|
||||
fbTex = nullptr;
|
||||
|
||||
if (fbTex) {
|
||||
fbTex->Release();
|
||||
fbTex = nullptr;
|
||||
}
|
||||
vdata->Release();
|
||||
vdata = nullptr;
|
||||
idata->Release();
|
||||
@@ -147,32 +140,38 @@ void SoftGPU::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat for
|
||||
|
||||
// Copies RGBA8 data from RAM to the currently bound render target.
|
||||
void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight) {
|
||||
using namespace Draw;
|
||||
|
||||
if (!draw_)
|
||||
return;
|
||||
float dstwidth = (float)PSP_CoreParameter().pixelWidth;
|
||||
float dstheight = (float)PSP_CoreParameter().pixelHeight;
|
||||
|
||||
Viewport viewport = {0.0f, 0.0f, dstwidth, dstheight, 0.0f, 1.0f};
|
||||
Draw::Viewport viewport = {0.0f, 0.0f, dstwidth, dstheight, 0.0f, 1.0f};
|
||||
draw_->SetViewports(1, &viewport);
|
||||
SamplerState *sampler;
|
||||
if (g_Config.iBufFilter == SCALE_NEAREST) {
|
||||
sampler = samplerNearest;
|
||||
} else {
|
||||
sampler = samplerLinear;
|
||||
}
|
||||
draw_->SetScissorRect(0, 0, dstwidth, dstheight);
|
||||
|
||||
float u0 = 0.0f;
|
||||
float u1;
|
||||
|
||||
if (fbTex) {
|
||||
fbTex->Release();
|
||||
fbTex = nullptr;
|
||||
}
|
||||
|
||||
Draw::TextureDesc desc{};
|
||||
desc.type = Draw::TextureType::LINEAR2D;
|
||||
desc.format = Draw::DataFormat::R8G8B8A8_UNORM;
|
||||
desc.depth = 1;
|
||||
desc.mipLevels = 1;
|
||||
bool hasImage = true;
|
||||
if (!Memory::IsValidAddress(displayFramebuf_)) {
|
||||
hasImage = false;
|
||||
u1 = 1.0f;
|
||||
} else if (displayFormat_ == GE_FORMAT_8888) {
|
||||
u8 *data = Memory::GetPointer(displayFramebuf_);
|
||||
fbTex->SetImageData(0, 0, 0, displayStride_, srcheight, 1, 0, displayStride_ * 4, data);
|
||||
desc.width = displayStride_;
|
||||
desc.height = srcheight;
|
||||
desc.initData.push_back(data);
|
||||
desc.format = Draw::DataFormat::R8G8B8A8_UNORM;
|
||||
u1 = (float)srcwidth / displayStride_;
|
||||
} else {
|
||||
// TODO: This should probably be converted in a shader instead..
|
||||
@@ -201,9 +200,16 @@ void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight) {
|
||||
}
|
||||
}
|
||||
|
||||
fbTex->SetImageData(0, 0, 0, srcwidth, srcheight, 1, 0, srcwidth * 4, (const uint8_t *)&fbTexBuffer[0]);
|
||||
desc.width = srcwidth;
|
||||
desc.height = srcheight;
|
||||
u1 = 1.0f;
|
||||
}
|
||||
if (!hasImage) {
|
||||
draw_->Clear(Draw::FB_COLOR_BIT, 0, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
fbTex = draw_->CreateTexture(desc);
|
||||
|
||||
float x, y, w, h;
|
||||
CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, dstwidth, dstheight, ROTATION_LOCKED_HORIZONTAL);
|
||||
@@ -224,46 +230,48 @@ void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight) {
|
||||
x2 -= 1.0f;
|
||||
y2 -= 1.0f;
|
||||
|
||||
if (hasImage) {
|
||||
float v0 = 1.0f;
|
||||
float v1 = 0.0f;
|
||||
float v0 = 1.0f;
|
||||
float v1 = 0.0f;
|
||||
|
||||
if (GetGPUBackend() == GPUBackend::VULKAN) {
|
||||
std::swap(v0, v1);
|
||||
}
|
||||
|
||||
draw_->BindSamplerStates(0, 1, &sampler);
|
||||
|
||||
const Vertex verts[4] = {
|
||||
{ x, y, 0, u0, v0, 0xFFFFFFFF }, // TL
|
||||
{ x, y2, 0, u0, v1, 0xFFFFFFFF }, // BL
|
||||
{ x2, y2, 0, u1, v1, 0xFFFFFFFF }, // BR
|
||||
{ x2, y, 0, u1, v0, 0xFFFFFFFF }, // TR
|
||||
};
|
||||
draw_->UpdateBuffer(vdata, (const uint8_t *)verts, 0, sizeof(verts), Draw::UPDATE_DISCARD);
|
||||
|
||||
int indexes[] = { 0, 1, 2, 0, 2, 3 };
|
||||
draw_->UpdateBuffer(idata, (const uint8_t *)indexes, 0, sizeof(indexes), Draw::UPDATE_DISCARD);
|
||||
|
||||
draw_->BindTexture(0, fbTex);
|
||||
|
||||
static const float identity4x4[16] = {
|
||||
1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f,
|
||||
};
|
||||
|
||||
VsTexColUB ub{};
|
||||
memcpy(ub.WorldViewProj, identity4x4, sizeof(float) * 16);
|
||||
draw_->BindPipeline(texColor);
|
||||
draw_->UpdateDynamicUniformBuffer(&ub, sizeof(ub));
|
||||
draw_->BindVertexBuffers(0, 1, &vdata, nullptr);
|
||||
draw_->BindIndexBuffer(idata, 0);
|
||||
draw_->DrawIndexed(6, 0);
|
||||
} else {
|
||||
draw_->Clear(Draw::FB_COLOR_BIT, 0, 0, 0);
|
||||
if (GetGPUBackend() == GPUBackend::VULKAN) {
|
||||
std::swap(v0, v1);
|
||||
}
|
||||
|
||||
Draw::SamplerState *sampler;
|
||||
if (g_Config.iBufFilter == SCALE_NEAREST) {
|
||||
sampler = samplerNearest;
|
||||
} else {
|
||||
sampler = samplerLinear;
|
||||
}
|
||||
draw_->BindSamplerStates(0, 1, &sampler);
|
||||
|
||||
const Vertex verts[4] = {
|
||||
{ x, y, 0, u0, v0, 0xFFFFFFFF }, // TL
|
||||
{ x, y2, 0, u0, v1, 0xFFFFFFFF }, // BL
|
||||
{ x2, y2, 0, u1, v1, 0xFFFFFFFF }, // BR
|
||||
{ x2, y, 0, u1, v0, 0xFFFFFFFF }, // TR
|
||||
};
|
||||
draw_->UpdateBuffer(vdata, (const uint8_t *)verts, 0, sizeof(verts), Draw::UPDATE_DISCARD);
|
||||
|
||||
int indexes[] = { 0, 1, 2, 0, 2, 3 };
|
||||
draw_->UpdateBuffer(idata, (const uint8_t *)indexes, 0, sizeof(indexes), Draw::UPDATE_DISCARD);
|
||||
|
||||
draw_->BindTexture(0, fbTex);
|
||||
|
||||
static const float identity4x4[16] = {
|
||||
1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f,
|
||||
};
|
||||
|
||||
Draw::VsTexColUB ub{};
|
||||
memcpy(ub.WorldViewProj, identity4x4, sizeof(float) * 16);
|
||||
draw_->BindPipeline(texColor);
|
||||
draw_->UpdateDynamicUniformBuffer(&ub, sizeof(ub));
|
||||
draw_->BindVertexBuffers(0, 1, &vdata, nullptr);
|
||||
draw_->BindIndexBuffer(idata, 0);
|
||||
draw_->DrawIndexed(6, 0);
|
||||
}
|
||||
|
||||
void SoftGPU::CopyDisplayToOutput()
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -412,6 +412,7 @@ void GameSettingsScreen::CreateViews() {
|
||||
CheckBox *softwareGPU = graphicsSettings->Add(new CheckBox(&g_Config.bSoftwareRendering, gr->T("Software Rendering", "Software Rendering (experimental)")));
|
||||
softwareGPU->OnClick.Add([=](EventParams &e) {
|
||||
settingInfo_->Show(gr->T("SoftGPU Tip", "Currently VERY slow"), e.v);
|
||||
bloomHackEnable_ = !g_Config.bSoftwareRendering && (g_Config.iInternalResolution != 1);
|
||||
return UI::EVENT_CONTINUE;
|
||||
});
|
||||
softwareGPU->OnClick.Handle(this, &GameSettingsScreen::OnSoftwareRendering);
|
||||
|
||||
@@ -476,12 +476,11 @@ void TextDrawer::DrawString(DrawBuffer &target, const char *str, float x, float
|
||||
|
||||
TextureDesc desc{};
|
||||
desc.type = TextureType::LINEAR2D;
|
||||
desc.format = Draw::DataFormat::R4G4B4A4_UNORM_PACK16;
|
||||
desc.format = Draw::DataFormat::B4G4R4A4_UNORM_PACK16;
|
||||
desc.width = entry->bmWidth;
|
||||
desc.height = entry->bmHeight;
|
||||
desc.depth = 1;
|
||||
desc.mipLevels = 1;
|
||||
entry->texture = draw_->CreateTexture(desc);
|
||||
|
||||
uint16_t *bitmapData = new uint16_t[entry->bmWidth * entry->bmHeight];
|
||||
for (int x = 0; x < entry->bmWidth; x++) {
|
||||
@@ -489,10 +488,9 @@ void TextDrawer::DrawString(DrawBuffer &target, const char *str, float x, float
|
||||
bitmapData[entry->bmWidth * y + x] = 0xfff0 | image.pixel(x, y) >> 28;
|
||||
}
|
||||
}
|
||||
entry->texture->SetImageData(0, 0, 0, entry->bmWidth, entry->bmHeight, 1, 0, entry->bmWidth * 2, (const uint8_t *)bitmapData);
|
||||
|
||||
desc.initData.push_back((uint8_t *)bitmapData);
|
||||
entry->texture = draw_->CreateTexture(desc);
|
||||
delete [] bitmapData;
|
||||
|
||||
cache_[entryHash] = std::unique_ptr<TextStringEntry>(entry);
|
||||
}
|
||||
float w = entry->bmWidth * fontScaleX_;
|
||||
|
||||
@@ -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,
|
||||
@@ -406,8 +406,6 @@ public:
|
||||
|
||||
class Texture : public RefCountedObject {
|
||||
public:
|
||||
virtual void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data) = 0;
|
||||
|
||||
int Width() { return width_; }
|
||||
int Height() { return height_; }
|
||||
int Depth() { return depth_; }
|
||||
|
||||
@@ -647,10 +647,6 @@ public:
|
||||
view->Release();
|
||||
}
|
||||
|
||||
void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data) {
|
||||
ELOG("SetImageData not supported, create a new texture instead");
|
||||
}
|
||||
|
||||
ID3D11Texture2D *tex = nullptr;
|
||||
ID3D11ShaderResourceView *view = nullptr;
|
||||
};
|
||||
|
||||
@@ -297,10 +297,10 @@ class D3D9Texture : public Texture {
|
||||
public:
|
||||
D3D9Texture(LPDIRECT3DDEVICE9 device, LPDIRECT3DDEVICE9EX deviceEx, const TextureDesc &desc);
|
||||
~D3D9Texture();
|
||||
void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data) override;
|
||||
void SetToSampler(LPDIRECT3DDEVICE9 device, int sampler);
|
||||
|
||||
private:
|
||||
void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data);
|
||||
bool Create(const TextureDesc &desc);
|
||||
LPDIRECT3DDEVICE9 device_;
|
||||
LPDIRECT3DDEVICE9EX deviceEx_;
|
||||
@@ -364,7 +364,7 @@ bool D3D9Texture::Create(const TextureDesc &desc) {
|
||||
|
||||
if (desc.initData.size()) {
|
||||
for (int i = 0; i < desc.initData.size(); i++) {
|
||||
this->SetImageData(0, 0, 0, width_, height_, depth_, i, 0, desc.initData[i]);
|
||||
SetImageData(0, 0, 0, width_, height_, depth_, i, 0, desc.initData[i]);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
+132
-113
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -656,75 +629,92 @@ inline bool isPowerOf2(int n) {
|
||||
|
||||
class OpenGLTexture : public Texture {
|
||||
public:
|
||||
OpenGLTexture(const TextureDesc &desc) : tex_(0), target_(TypeToTarget(desc.type)), format_(desc.format), mipLevels_(desc.mipLevels) {
|
||||
generatedMips_ = false;
|
||||
canWrap_ = true;
|
||||
width_ = desc.width;
|
||||
height_ = desc.height;
|
||||
depth_ = desc.depth;
|
||||
canWrap_ = !isPowerOf2(width_) || !isPowerOf2(height_);
|
||||
OpenGLTexture(const TextureDesc &desc);
|
||||
~OpenGLTexture();
|
||||
|
||||
glGenTextures(1, &tex_);
|
||||
|
||||
if (!desc.initData.size())
|
||||
return;
|
||||
|
||||
int level = 0;
|
||||
for (auto data : desc.initData) {
|
||||
SetImageData(0, 0, 0, width_, height_, depth_, level, 0, data);
|
||||
width_ = (width_ + 1) /2;
|
||||
height_ = (height_ + 1) /2;
|
||||
level++;
|
||||
}
|
||||
if (desc.initData.size() < desc.mipLevels)
|
||||
AutoGenMipmaps();
|
||||
}
|
||||
~OpenGLTexture() {
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void Destroy() {
|
||||
if (tex_) {
|
||||
glDeleteTextures(1, &tex_);
|
||||
tex_ = 0;
|
||||
generatedMips_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data) override;
|
||||
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:
|
||||
GLuint tex_;
|
||||
GLuint target_;
|
||||
void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data);
|
||||
|
||||
GLuint tex_ = 0;
|
||||
GLuint target_ = 0;
|
||||
|
||||
DataFormat format_;
|
||||
TextureType type_;
|
||||
int mipLevels_;
|
||||
bool generatedMips_;
|
||||
bool canWrap_;
|
||||
};
|
||||
|
||||
Texture *OpenGLContext::CreateTexture(const TextureDesc &desc) {
|
||||
return new OpenGLTexture(desc);
|
||||
OpenGLTexture::OpenGLTexture(const TextureDesc &desc) {
|
||||
generatedMips_ = false;
|
||||
canWrap_ = true;
|
||||
width_ = desc.width;
|
||||
height_ = desc.height;
|
||||
depth_ = desc.depth;
|
||||
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);
|
||||
width_ = (width_ + 1) / 2;
|
||||
height_ = (height_ + 1) / 2;
|
||||
level++;
|
||||
}
|
||||
mipLevels_ = level;
|
||||
|
||||
#ifdef USING_GLES2
|
||||
if (gl_extensions.GLES3) {
|
||||
glTexParameteri(target_, GL_TEXTURE_MAX_LEVEL, level - 1);
|
||||
}
|
||||
#else
|
||||
glTexParameteri(target_, GL_TEXTURE_MAX_LEVEL, level - 1);
|
||||
#endif
|
||||
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) {
|
||||
ILOG("Generating mipmaps");
|
||||
AutoGenMipmaps();
|
||||
}
|
||||
|
||||
// Unbind.
|
||||
glBindTexture(target_, 0);
|
||||
}
|
||||
|
||||
OpenGLTexture::~OpenGLTexture() {
|
||||
if (tex_) {
|
||||
glDeleteTextures(1, &tex_);
|
||||
tex_ = 0;
|
||||
generatedMips_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -747,12 +737,11 @@ void OpenGLTexture::SetImageData(int x, int y, int z, int width, int height, int
|
||||
format = GL_RGBA;
|
||||
type = GL_UNSIGNED_BYTE;
|
||||
break;
|
||||
case DataFormat::R4G4B4A4_UNORM_PACK16:
|
||||
case DataFormat::B4G4R4A4_UNORM_PACK16:
|
||||
internalFormat = GL_RGBA;
|
||||
format = GL_RGBA;
|
||||
type = GL_UNSIGNED_SHORT_4_4_4_4;
|
||||
break;
|
||||
|
||||
#ifndef USING_GLES2
|
||||
case DataFormat::A4B4G4R4_UNORM_PACK16:
|
||||
internalFormat = GL_RGBA;
|
||||
@@ -760,18 +749,11 @@ void OpenGLTexture::SetImageData(int x, int y, int z, int width, int height, int
|
||||
type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
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);
|
||||
@@ -787,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_);
|
||||
@@ -852,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];
|
||||
@@ -980,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);
|
||||
@@ -1102,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);
|
||||
|
||||
@@ -1111,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_);
|
||||
|
||||
@@ -1121,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);
|
||||
@@ -1639,12 +1656,14 @@ uint32_t OpenGLContext::GetDataFormatSupport(DataFormat fmt) const {
|
||||
switch (fmt) {
|
||||
case DataFormat::B8G8R8A8_UNORM:
|
||||
return FMT_RENDERTARGET | FMT_TEXTURE;
|
||||
case DataFormat::R4G4B4A4_UNORM_PACK16:
|
||||
return FMT_RENDERTARGET | FMT_TEXTURE;
|
||||
case DataFormat::B4G4R4A4_UNORM_PACK16:
|
||||
return 0; // native support
|
||||
return FMT_RENDERTARGET | FMT_TEXTURE; // native support
|
||||
case DataFormat::A4B4G4R4_UNORM_PACK16:
|
||||
return 0; // Can support this if _REV formats are supported.
|
||||
#ifndef USING_GLES2
|
||||
// Can support this if _REV formats are supported.
|
||||
return FMT_TEXTURE;
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
case DataFormat::R8G8B8A8_UNORM:
|
||||
return FMT_RENDERTARGET | FMT_TEXTURE | FMT_INPUTLAYOUT;
|
||||
|
||||
@@ -597,11 +597,11 @@ public:
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data) override;
|
||||
|
||||
VkImageView GetImageView() { return vkTex_->GetImageView(); }
|
||||
|
||||
private:
|
||||
void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data);
|
||||
|
||||
bool Create(const TextureDesc &desc) {
|
||||
format_ = desc.format;
|
||||
mipLevels_ = desc.mipLevels;
|
||||
|
||||
Reference in New Issue
Block a user