thunderbrew/src/gx/gll/GLMipmap.cpp
2023-03-04 11:29:25 -06:00

492 lines
14 KiB
C++

#include "gx/gll/GLMipmap.h"
#include "gx/gll/GLCommand.h"
#include "gx/gll/GLDevice.h"
#include "gx/gll/GLFramebuffer.h"
#include <bc/Debug.hpp>
int32_t GLMipmap::GetDepthBits() {
return this->m_DepthBits;
}
void GLMipmap::Attach(GLFramebuffer* framebuffer, GLenum attachPoint, int32_t a4) {
if (!this->m_AttachPoints) {
this->m_AttachPoints = new std::vector<GLAttachPoint>();
}
auto& attachPoints = *this->m_AttachPoints;
auto framebufferID = framebuffer->m_FramebufferID;
if (framebufferID >= attachPoints.size()) {
attachPoints.resize(framebufferID + 1);
} else {
BLIZZARD_ASSERT(attachPoints[framebufferID].framebuffer != framebuffer || attachPoints[framebufferID].point != attachPoint);
auto& attach = attachPoints[framebufferID];
if (
attach.point
&& (attach.point != GL_DEPTH_ATTACHMENT || attachPoint != GL_STENCIL_ATTACHMENT)
&& (attach.point != GL_STENCIL_ATTACHMENT || attachPoint != GL_DEPTH_ATTACHMENT)
) {
framebuffer->Detach(attach.point);
}
}
GLDevice* device = GLDevice::Get();
auto currentTarget = device->GetCurrentTarget();
device->BindFramebuffer(framebuffer);
if (framebufferID) {
if (this->m_Target == GL_TEXTURE_3D) {
glFramebufferTexture3DEXT(
GL_FRAMEBUFFER,
attachPoint,
GL_TEXTURE_3D,
this->m_Texture->m_TextureID,
this->m_Level,
a4
);
} else {
glFramebufferTexture2DEXT(
GL_FRAMEBUFFER,
attachPoint,
this->m_Target,
this->m_Texture->m_TextureID,
this->m_Level
);
}
}
if (attachPoint == GL_DEPTH_ATTACHMENT && !this->m_DepthBits) {
GLint depthBits = 0;
glGetIntegerv(GL_DEPTH_BITS, &depthBits);
this->m_DepthBits = depthBits;
}
device->BindFramebuffer(currentTarget);
auto& attach = attachPoints[framebufferID];
attach.framebuffer = framebuffer;
attach.zOffset = a4;
if (
(attach.point != GL_DEPTH_ATTACHMENT || attachPoint != GL_STENCIL_ATTACHMENT)
&& (attach.point != GL_STENCIL_ATTACHMENT || attachPoint != GL_DEPTH_ATTACHMENT)
) {
attach.point = attachPoint;
} else {
attach.point = GL_DEPTH_STENCIL;
}
}
void GLMipmap::Detach(GLFramebuffer* framebuffer, GLenum attachPoint, bool a4) {
GLuint framebufferID = framebuffer->m_FramebufferID;
auto& attachPoints = *this->m_AttachPoints;
BLIZZARD_ASSERT(attachPoints.size() >= framebufferID);
BLIZZARD_ASSERT(attachPoints[framebufferID].framebuffer == framebuffer);
if (!a4 && framebufferID) {
GLDevice* v12 = GLDevice::Get();
GLFramebuffer* v14 = v12->GetCurrentTarget();
v12->BindFramebuffer(framebuffer);
if (this->m_Target == GL_TEXTURE_3D) {
glFramebufferTexture3DEXT(GL_FRAMEBUFFER, attachPoint, GL_TEXTURE_3D, 0, 0, 0);
} else {
glFramebufferTexture2DEXT(GL_FRAMEBUFFER, attachPoint, this->m_Target, 0, 0);
}
v12->BindFramebuffer(v14);
}
GLAttachPoint* v9 = &attachPoints[framebufferID];
if (v9->point == GL_DEPTH_STENCIL) {
BLIZZARD_ASSERT(this->GetFormat() == GLTF_D24S8);
if (attachPoint == GL_DEPTH_ATTACHMENT) {
v9->point = GL_STENCIL_ATTACHMENT;
} else if (attachPoint == GL_STENCIL_ATTACHMENT) {
v9->point = GL_DEPTH_ATTACHMENT;
} else {
BLIZZARD_ASSERT(false);
}
} else {
BLIZZARD_ASSERT(attachPoints[framebufferID].point == attachPoint);
v9->framebuffer = 0;
v9->point = 0;
v9->zOffset = 0;
// TODO
// this->m_Texture->m_TimeStamp = Blizzard::Time::GetTimestamp();
}
}
void GLMipmap::DetachAll() {
if (!this->m_AttachPoints) {
return;
}
auto& attachPoints = *this->m_AttachPoints;
for (int32_t i = 0; i < attachPoints.size(); i++) {
BLIZZARD_ASSERT(attachPoints[i].point != GL_ZERO);
BLIZZARD_ASSERT(attachPoints[i].framebuffer->m_FramebufferID == i);
attachPoints[i].framebuffer->Detach(attachPoints[i].point);
}
}
GLTextureFormat GLMipmap::GetFormat() {
return this->m_Texture->GetFormat();
}
TextureFormatInfo& GLMipmap::GetFormatInfo() {
return this->m_Texture->GetFormatInfo();
};
uint16_t GLMipmap::GetHeight() {
return this->m_Height;
}
int32_t GLMipmap::GetPitch() {
int32_t bpp = this->GetFormatInfo().m_BytePerPixel;
int32_t v4 = this->m_Texture->var12 >> this->m_Level;
return v4 >= bpp ? v4 : bpp;
}
GLTexture* GLMipmap::GetTexture() {
return this->m_Texture;
}
uint32_t GLMipmap::GetTextureID() {
return this->m_Texture->m_TextureID;
}
uint16_t GLMipmap::GetWidth() {
return this->m_Width;
}
void* GLMipmap::Map(GLEnum mode, const GLBox* area) {
BLIZZARD_ASSERT(!this->m_Texture->IsSystemBuffer());
BLIZZARD_ASSERT(this->m_Data != nullptr);
BLIZZARD_ASSERT(!this->m_Texture->IsRenderTarget());
BLIZZARD_ASSERT(mode != GL_ZERO);
BLIZZARD_ASSERT(this->m_MapParams == nullptr);
if (mode != GL_READ_ONLY) {
this->m_Texture->m_MappedMipmaps++;
}
MapParams* mapParams = new MapParams();
this->m_MapParams = mapParams;
if (area) {
BLIZZARD_ASSERT(area->width > 0);
BLIZZARD_ASSERT(area->height > 0);
BLIZZARD_ASSERT(area->depth > 0);
BLIZZARD_ASSERT(!this->GetFormatInfo().m_IsCompressed || ((area->top & 0x3) == 0 && (area->left & 0x3) == 0 && (area->width & 0x3) == 0 && (area->height & 0x3) == 0));
BLIZZARD_ASSERT((area->height + area->top) <= this->m_Height);
BLIZZARD_ASSERT((area->depth + area->front) <= this->m_Depth);
BLIZZARD_ASSERT((area->width + area->left) <= this->m_Width);
mapParams->m_MapArea = {
area->left,
area->top,
area->front,
area->width,
area->height,
area->depth
};
int32_t size = this->GetFormatInfo().m_BytePerPixel
* this->m_Width
* mapParams->m_MapArea.depth
* mapParams->m_MapArea.height;
mapParams->m_Size = this->GetFormatInfo().m_IsCompressed
? size >> 4
: size;
mapParams->m_Unk7 = (this->GetFormatInfo().m_BytePerPixel * mapParams->m_MapArea.left)
>> this->GetFormatInfo().m_IsCompressed ? 2 : 0;
} else {
mapParams->m_MapArea = {
0,
0,
0,
this->m_Width,
this->m_Height,
this->m_Depth
};
mapParams->m_Size = this->m_Size;
mapParams->m_Unk7 = 0;
}
mapParams->m_MapMode = mode;
int32_t rowPitch = this->GetPitch();
BLIZZARD_ASSERT(((mapParams->m_MapArea.top * rowPitch) + mapParams->m_MapArea.left * this->GetFormatInfo().m_BytePerPixel) < (this->GetFormatInfo().m_IsCompressed ? this->m_Size << 4 : this->m_Size));
int32_t v22 = rowPitch * this->m_Height;
if (this->GetFormatInfo().m_IsCompressed) {
v22 >>= 2;
}
unsigned char* v24 = this->m_Data
+ ((mapParams->m_MapArea.top * rowPitch) >> (this->GetFormatInfo().m_IsCompressed ? 2 : 0))
+ (mapParams->m_MapArea.front * v22);
mapParams->m_Unk8 = v24;
return v24 + mapParams->m_Unk7;
}
void* GLMipmap::Map(GLEnum mode, const GLRect* rect) {
if (rect) {
GLBox area = {
rect->left,
rect->top,
0,
rect->width,
rect->height,
1
};
return this->Map(mode, &area);
} else {
return this->Map(mode, static_cast<GLBox*>(nullptr));
}
}
void GLMipmap::ReleaseObject() {
BLIZZARD_ASSERT(this->m_MapParams == nullptr);
this->RemoveDebugMipmap();
this->DetachAll();
if (this->m_AttachPoints) {
delete this->m_AttachPoints;
}
this->m_AttachPoints = nullptr;
this->m_Unk24 = 0;
}
void GLMipmap::RemoveDebugMipmap() {
// TODO
}
void GLMipmap::ResetData(GLEnum target, int32_t level, unsigned char* data) {
BLIZZARD_ASSERT(this->m_Target != GL_TEXTURE_3D || !this->GetFormatInfo().m_IsCompressed);
this->m_Target = target;
this->m_Level = level;
this->m_Data = data;
BLIZZARD_ASSERT(this->GetFormat() != GLTF_INVALID);
BLIZZARD_ASSERT(this->GetFormat() < GLTF_NUM_TEXTURE_FORMATS);
if (!this->m_Texture->IsSystemBuffer() && this->m_Texture->IsRenderTarget()) {
BLIZZARD_ASSERT(!this->GetFormatInfo().m_IsCompressed);
this->TexImage(nullptr);
this->m_Unk24 = 1;
}
}
void GLMipmap::ResetSize(uint32_t width, uint32_t height, uint32_t depth) {
this->m_Width = width ? width : 1;
this->m_Height = height ? height : 1;
this->m_Depth = depth ? depth : 1;
if (this->GetFormatInfo().m_IsCompressed) {
BLIZZARD_ASSERT(this->m_Depth == 1);
this->m_Width = (this->m_Width + 3) & 0xFFFC;
this->m_Height = (this->m_Height + 3) & 0xFFFC;
}
uint32_t v11 = this->GetFormatInfo().m_BytePerPixel;
uint32_t v20 = this->m_Texture->var12 >> this->m_Level;
if (v20 >= v11) {
v11 = v20;
}
uint32_t v15 = v11 * this->m_Height;
uint32_t v12;
if (this->GetFormatInfo().m_IsCompressed) {
v12 = v15 >> 2;
} else {
v12 = v15;
}
this->m_Size = this->m_Depth * v12;
}
void GLMipmap::TexImage(const void* pixels) {
BLIZZARD_ASSERT((this->m_Texture->IsRenderTarget() || pixels != nullptr) && GLDevice::Get()->GetVertexArrayStates().buffers[eGLBT_PIXEL_UNPACK] == 0);
if (this->m_Target == GL_TEXTURE_3D) {
glTexImage3D(
GL_TEXTURE_3D,
this->m_Level,
this->GetFormatInfo().m_InternalFormat,
this->m_Width,
this->m_Height,
this->m_Depth,
0,
this->GetFormatInfo().m_DataFormat,
this->GetFormatInfo().m_DataType,
pixels
);
} else if (this->GetFormatInfo().m_IsCompressed) {
glCompressedTexImage2D(
this->m_Target,
this->m_Level,
this->GetFormatInfo().m_InternalFormat,
this->m_Width,
this->m_Height,
0,
this->m_Size,
pixels
);
} else {
glTexImage2D(
this->m_Target,
this->m_Level,
this->GetFormatInfo().m_InternalFormat,
this->m_Width,
this->m_Height,
0,
this->GetFormatInfo().m_DataFormat,
this->GetFormatInfo().m_DataType,
pixels
);
}
}
void GLMipmap::TexSubImage(const GLBox& a2, int32_t size, const void* pixels) {
BLIZZARD_ASSERT(!this->m_Texture->IsRenderTarget() && pixels != nullptr && GLDevice::Get()->GetVertexArrayStates().buffers[eGLBT_PIXEL_UNPACK] == 0);
if (this->m_Target == GL_TEXTURE_3D) {
glPixelStorei(GL_UNPACK_ROW_LENGTH, this->m_Width);
glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, this->m_Height);
glTexSubImage3D(
this->m_Target,
this->m_Level,
a2.left,
a2.top,
a2.front,
a2.width,
a2.height,
a2.depth,
this->GetFormatInfo().m_DataFormat,
this->GetFormatInfo().m_DataType,
pixels
);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
} else if (this->GetFormatInfo().m_IsCompressed) {
glCompressedTexSubImage2D(
this->m_Target,
this->m_Level,
0,
a2.top,
this->m_Width,
a2.height,
this->GetFormatInfo().m_InternalFormat,
size,
pixels
);
} else {
glPixelStorei(GL_UNPACK_ROW_LENGTH, this->m_Width);
glTexSubImage2D(
this->m_Target,
this->m_Level,
a2.left,
a2.top,
a2.width,
a2.height,
this->GetFormatInfo().m_DataFormat,
this->GetFormatInfo().m_DataType,
pixels
);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
}
}
void GLMipmap::Unmap() {
BLIZZARD_ASSERT(!this->m_Texture->IsRenderTarget());
BLIZZARD_ASSERT(!this->m_Texture->IsSystemBuffer());
BLIZZARD_ASSERT(this->m_MapParams != nullptr);
if (this->m_MapParams->m_MapMode == GL_READ_ONLY) {
delete this->m_MapParams;
this->m_MapParams = nullptr;
return;
}
GLDevice* device = GLDevice::Get();
BLIZZARD_ASSERT(this->m_Texture->m_MappedMipmaps > 0);
if (device->m_TexWorker) {
device->m_TexWorker->Lock();
GLTexUnmap* command = new GLTexUnmap(this->m_Texture, this, this->m_MapParams);
device->m_TexWorker->Send(command);
device->m_TexWorker->Signal();
device->m_TexWorker->Unlock();
} else {
this->Unmap(this->m_MapParams);
}
this->m_MapParams = nullptr;
}
void GLMipmap::Unmap(MapParams* mapParams) {
BLIZZARD_ASSERT(mapParams != nullptr);
this->m_Texture->Bind(nullptr, 0);
if (this->m_Unk24) {
if (this->GetFormatInfo().m_IsCompressed) {
GLBox area = {
0,
mapParams->m_MapArea.top,
mapParams->m_MapArea.front,
this->m_Width,
mapParams->m_MapArea.height,
mapParams->m_MapArea.depth
};
this->TexSubImage(area, mapParams->m_Size, mapParams->m_Unk8);
} else {
this->TexSubImage(mapParams->m_MapArea, mapParams->m_Size, mapParams->m_Unk8 + mapParams->m_Unk7);
}
} else {
this->TexImage(this->m_Data);
this->m_Unk24 = 1;
}
delete mapParams;
// TODO
this->m_Texture->m_MappedMipmaps--;
}