mirror of
https://github.com/thunderbrewhq/thunderbrew
synced 2025-10-29 07:16:05 +03:00
492 lines
14 KiB
C++
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--;
|
|
}
|