实现虚拟纹理的异步加载

dev-VirtualTexture
wuyize 2023-02-25 13:34:24 +08:00
parent b23d55e876
commit 8920dc39ad
9 changed files with 201 additions and 104 deletions

View File

@ -71,6 +71,7 @@
<AdditionalIncludeDirectories>$(ProjectDir)include;$(SolutionDir)ArchitectureColoredPainting\src\Editor\RightBar;$(SolutionDir)ArchitectureColoredPainting\src\Editor\;$(SolutionDir)FramelessHelper\include;$(SolutionDir)FramelessHelper\qmake\inc\core;$(SolutionDir)FramelessHelper\include\FramelessHelper\Core;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>FRAMELESSHELPER_WIDGETS_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>Level1</WarningLevel>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
</ClCompile>
<Link>
<AdditionalDependencies>opengl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
@ -81,7 +82,7 @@
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<Optimization>Disabled</Optimization>
<Optimization>MaxSpeed</Optimization>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
</ClCompile>
<Link>

View File

@ -182,8 +182,8 @@ std::tuple<GLuint, GLuint, GLuint, GLuint> Renderer::IblUtils::precomputeCubemap
// ----------------------
unsigned int captureFBO;
unsigned int captureRBO;
glFunc->glGenFramebuffers(1, &captureFBO);
glFunc->glGenRenderbuffers(1, &captureRBO);
glFunc->glCreateFramebuffers(1, &captureFBO);
glFunc->glCreateRenderbuffers(1, &captureRBO);
glFunc->glBindFramebuffer(GL_FRAMEBUFFER, captureFBO);
glFunc->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, captureRBO);
@ -262,6 +262,8 @@ GLuint Renderer::IblUtils::generateCubemap(QOpenGLFunctions_4_5_Core* glFunc, GL
glFunc->glActiveTexture(GL_TEXTURE0);
glFunc->glBindTexture(GL_TEXTURE_2D, hdrTexture);
glFunc->glBindRenderbuffer(GL_RENDERBUFFER, captureRBO);
glFunc->glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, cubemapSize, cubemapSize);
glFunc->glViewport(0, 0, cubemapSize, cubemapSize);
glFunc->glBindFramebuffer(GL_FRAMEBUFFER, captureFBO);
@ -285,8 +287,6 @@ GLuint Renderer::IblUtils::generateCubemap(QOpenGLFunctions_4_5_Core* glFunc, GL
GLuint Renderer::IblUtils::generateIrradianceMap(QOpenGLFunctions_4_5_Core* glFunc, GLuint captureFBO, GLuint captureRBO, const QMatrix4x4& captureProjection, const std::array<QMatrix4x4, 6>& captureViews, GLuint envCubemap)
{
constexpr int irradianceMapSize = 32;
// pbr: create an irradiance cubemap, and re-scale capture FBO to irradiance scale.
// --------------------------------------------------------------------------------
unsigned int irradianceMap;
@ -337,8 +337,6 @@ GLuint Renderer::IblUtils::generateIrradianceMap(QOpenGLFunctions_4_5_Core* glFu
GLuint Renderer::IblUtils::generatePrefilterMap(QOpenGLFunctions_4_5_Core* glFunc, GLuint captureFBO, GLuint captureRBO, const QMatrix4x4& captureProjection, const std::array<QMatrix4x4, 6>& captureViews, GLuint envCubemap)
{
constexpr int prefilterMapSize = 128;
// pbr: create a pre-filter cubemap, and re-scale capture FBO to pre-filter scale.
// --------------------------------------------------------------------------------
unsigned int prefilterMap;

View File

@ -7,6 +7,8 @@ namespace Renderer
{
public:
static constexpr int cubemapSize = 1024;
static constexpr int irradianceMapSize = 32;
static constexpr int prefilterMapSize = 128;
static void renderCube(QOpenGLFunctions_4_5_Core* glFunc);
static void renderSphere(QOpenGLFunctions_4_5_Core* glFunc);
/**

View File

@ -311,18 +311,20 @@ GLuint Renderer::Model::loadPainting(std::string path)
std::make_shared<Element>(Element{ contour[2], style[0]}),
};
Painting painting;
//for (int i = 0; i < 3; i++)
//{
// float x = (float)rand() / RAND_MAX * 2 - 1;
// float y = (float)rand() / RAND_MAX * 2 - 1;
// float z = 0.05 + x;//(float)rand() / RAND_MAX * (0.1) + x;
// float w = 0.05 + y;//(float)rand() / RAND_MAX * (0.1) + y;
// //rootBvhTreeData.push_back(BvhTreeData(QVector4D(x, y, z, w), 0, encodeZIndexAngle(1, (float)rand() / RAND_MAX * 360)));
// painting.addElement(element[i%3], QVector4D(x, y, z, w), (float)rand() / RAND_MAX * 360, 1);
//}
painting.addElement(*element[0], ElementTransform{ glm::vec2(-0.5,-0.45), glm::vec2(0.6,0.7), 45, glm::bvec2(true, false), 0 });
painting.addElement(*element[1], ElementTransform{ glm::vec2(-0.45,0.45), glm::vec2(0.5,0.5), 0, glm::bvec2(false), 0 });
painting.addElement(*element[2], ElementTransform{ glm::vec2(0.5,-0.45), glm::vec2(0.6,0.7), 0, glm::bvec2(false), 0 });
for (int i = 0; i < 1000; i++)
{
float x = (float)rand() / RAND_MAX * 2 - 1;
float y = (float)rand() / RAND_MAX * 2 - 1;
float z = 0.05 + x;//(float)rand() / RAND_MAX * (0.1) + x;
float w = 0.05 + y;//(float)rand() / RAND_MAX * (0.1) + y;
//rootBvhTreeData.push_back(BvhTreeData(QVector4D(x, y, z, w), 0, encodeZIndexAngle(1, (float)rand() / RAND_MAX * 360)));
//painting.addElement(element[i%3], QVector4D(x, y, z, w), (float)rand() / RAND_MAX * 360, 1);
painting.addElement(*element[i%3], ElementTransform{ glm::vec2(x,y), glm::vec2(0.05), (float)rand() / RAND_MAX * 360, glm::bvec2(false), 0 });
}
//painting.addElement(*element[0], ElementTransform{ glm::vec2(-0.5,-0.45), glm::vec2(0.6,0.7), 45, glm::bvec2(true, false), 0 });
//painting.addElement(*element[1], ElementTransform{ glm::vec2(-0.45,0.45), glm::vec2(0.5,0.5), 0, glm::bvec2(false), 0 });
//painting.addElement(*element[2], ElementTransform{ glm::vec2(0.5,-0.45), glm::vec2(0.6,0.7), 0, glm::bvec2(false), 0 });
//painting.addElement(element[0], QVector4D(-0.8, -0.8, -0.2, -0.1), 0, 0);

View File

@ -26,8 +26,9 @@ RendererGLWidget::RendererGLWidget(QWidget* parent)
//startTimer();
lastFrame = std::clock();
setFocusPolicy(Qt::StrongFocus);
QSurfaceFormat format;
format.setSwapInterval(0);
//QSurfaceFormat format;
//format.setProfile(QSurfaceFormat::CoreProfile);
////format.setSwapInterval(0);
//setFormat(format);
}
@ -60,7 +61,10 @@ void RendererGLWidget::startTimer()
{
//startTimer(1000 / QGuiApplication::primaryScreen()->refreshRate());
if (timerId == -1)
{
timerId = QObject::startTimer(1);
}
}
void RendererGLWidget::stopTimer()
@ -102,7 +106,7 @@ void Renderer::RendererGLWidget::setExposure(float exposure)
QOpenGLTexture randomMap(QOpenGLTexture::Target2D);
void GLAPIENTRY MessageCallback(GLenum source,
void GLAPIENTRY messageCallback(GLenum source,
GLenum type,
GLuint id,
GLenum severity,
@ -128,7 +132,8 @@ void RendererGLWidget::initializeGL()
qDebug() << "GL_VERSION" << (char*)gl->GetString(GL_VERSION);
gl->Enable(GL_DEBUG_OUTPUT);
gl->DebugMessageCallback(MessageCallback, 0);
//gl->Enable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
gl->DebugMessageCallback(messageCallback, 0);
gl->Enable(GL_DEPTH_TEST);
gl->DepthFunc(GL_LEQUAL);
@ -252,6 +257,7 @@ void RendererGLWidget::initializeGL()
finalProgramPtr->release();
vtManager = std::make_unique<VirtualTextureManager>(gl.get());
paintingHelper = new PaintingHelper(glFunc);
model = new Model(context(), modelProgramPtr, paintingProgramPtr, shadowProgramPtr, paintingHelper, vtManager.get());
@ -283,17 +289,28 @@ void RendererGLWidget::initializeGL()
reinterpret_cast<void*>(3 * sizeof(GLfloat)));
quadVBO.release();
gl->GenQueries(1, &timeQuery);
}
void RendererGLWidget::paintGL()
{
QOpenGLFunctions_4_5_Core* glFunc = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_4_5_Core>();
GLuint timeQuery;
gl->GenQueries(1, &timeQuery);
gl->BeginQuery(GL_TIME_ELAPSED, timeQuery);
pageIdDownsampleProgramPtr->bind();
gl->BindImageTexture(3, gbuffers[4], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RG16UI);
gl->DispatchCompute(ceil(frameWidth / 8. / 8.), ceil(frameWidth / 8. / 8.), 1);
pageIdDownsampleProgramPtr->release();
std::vector<glm::u16vec2> pixels;
pixels.resize(ceil(frameWidth / 8.) * ceil(frameHeight / 8.));
fboPtr->bind();
gl->ReadBuffer(GL_COLOR_ATTACHMENT4);
gl->ReadnPixels(0, 0, ceil(frameWidth / 8.), ceil(frameHeight / 8.), GL_RG_INTEGER, GL_UNSIGNED_SHORT, pixels.size() * sizeof(glm::u16vec2), pixels.data());
//gl->GetTextureSubImage(gbuffers[4], 0, 0, 0, 0, ceil(frameWidth / 8.), ceil(frameHeight / 8.), 1, GL_RG_INTEGER, GL_UNSIGNED_SHORT, pixels.size() * sizeof(glm::u16vec2), pixels.data());
fboPtr->release();
vtManager->tryUpdatePages(pixels);
gl->BeginQuery(GL_TIME_ELAPSED, timeQuery);
gl->Enable(GL_CULL_FACE);
@ -311,6 +328,7 @@ void RendererGLWidget::paintGL()
}
gl->BindBuffer(GL_UNIFORM_BUFFER, 0);
vtManager->commitMutex.lock();
{
gl->BindFramebuffer(GL_FRAMEBUFFER, shadowFboHandle);
gl->Viewport(0, 0, shadowMapResolution, shadowMapResolution);
@ -365,20 +383,10 @@ void RendererGLWidget::paintGL()
}
}
plainProgramPtr->release();
pageIdDownsampleProgramPtr->bind();
gl->BindImageTexture(3, gbuffers[4], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RG16UI);
gl->DispatchCompute(ceil(frameWidth / 8. / 8.), ceil(frameWidth / 8. / 8.), 1);
pageIdDownsampleProgramPtr->release();
std::vector<glm::u16vec2> pixels;
pixels.resize(ceil(frameWidth / 8.) * ceil(frameHeight / 8.));
gl->ReadBuffer(GL_COLOR_ATTACHMENT4);
gl->ReadnPixels(0, 0, ceil(frameWidth / 8.), ceil(frameHeight / 8.), GL_RG_INTEGER, GL_UNSIGNED_SHORT, pixels.size() * sizeof(glm::u16vec2), pixels.data());
vtManager->updatePages(pixels);
fboPtr->release();
}
gl->Finish();
vtManager->commitMutex.unlock();
//depthInitProgramPtr->bind();
//gl->ActiveTexture(GL_TEXTURE0);
@ -479,7 +487,8 @@ void RendererGLWidget::paintGL()
if (accTime > 1.)
{
std::cout << std::format("{:20}\r", "");
std::cout << std::format("FPS: {:.2f}({:.2f}ms) Pos: {:.2f},{:.2f},{:.2f}\r", frameCnt / accTime, averageDuration / 1e6 / frameCnt, camera.Position.x(), camera.Position.y(), camera.Position.z());
std::cout << std::format("FPS: {:.2f}({:.2f}ms) Page: {:}ms Pos: {:.2f},{:.2f},{:.2f}\r", frameCnt / accTime, averageDuration / 1e6 / frameCnt, vtManager->pageLoadDuration / 1e6, camera.Position.x(), camera.Position.y(), camera.Position.z());
vtManager->pageLoadDuration = 0;
accTime = 0;
frameCnt = 0;
averageDuration = 0;
@ -583,8 +592,8 @@ void RendererGLWidget::resizeGL(int width, int height)
gl->TexImage2D(GL_TEXTURE_2D, i, GL_R32F, depthWidth / pow(2, i), depthHeight / pow(2, i), 0, GL_RED, GL_FLOAT, NULL);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 6);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST_MIPMAP_NEAREST);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
gl->TexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, std::begin({ 1.0f, 1.0f, 1.0f, 1.0f }));

View File

@ -80,5 +80,7 @@ namespace Renderer
Model* model = nullptr;
PaintingHelper* paintingHelper;
std::unique_ptr<VirtualTextureManager> vtManager;
GLuint timeQuery;
};
}

View File

@ -1,49 +1,97 @@
#include <glad/gl.h>
#include "VirtualTextureManager.h"
#include <QOffscreenSurface>
#include <array>
#include <QDebug>
#include <stb_image.h>
#include <glm/gtc/integer.hpp>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/component_wise.hpp>
std::mutex pageIdBufferMutex;
Renderer::VirtualTextureManager::VirtualTextureManager(GladGLContext* gl)
:gl(gl)
Renderer::VirtualTextureManager::VirtualTextureManager(GladGLContext* glMain)
:glMain(glMain)
{
GLint numPageSizes;
auto mainContext = QOpenGLContext::currentContext();
auto mainSurface = mainContext->surface();
surface.setFormat(mainContext->format());
surface.create();
mainContext->doneCurrent();
// Figure out how many page sizes are available for a 2D texture
gl->GetInternalformativ(GL_TEXTURE_2D, GL_RGBA8, GL_NUM_VIRTUAL_PAGE_SIZES_ARB, sizeof(GLint), &numPageSizes);
std::vector<GLint> pageSizesX(numPageSizes);
std::vector<GLint> pageSizesY(numPageSizes);
std::vector<GLint> pageSizesZ(numPageSizes);
gl->GetInternalformativ(GL_TEXTURE_2D, GL_RGBA8, GL_VIRTUAL_PAGE_SIZE_X_ARB, numPageSizes * sizeof(GLint), pageSizesX.data());
gl->GetInternalformativ(GL_TEXTURE_2D, GL_RGBA8, GL_VIRTUAL_PAGE_SIZE_Y_ARB, numPageSizes * sizeof(GLint), pageSizesY.data());
gl->GetInternalformativ(GL_TEXTURE_2D, GL_RGBA8, GL_VIRTUAL_PAGE_SIZE_Z_ARB, numPageSizes * sizeof(GLint), pageSizesZ.data());
qDebug() << "RGBA8" << numPageSizes;
for (int i = 0; i < numPageSizes; i++)
qDebug() << pageSizesX[i] << pageSizesY[i] << pageSizesZ[i];
thread = std::jthread([&] {
QOpenGLContext context;
context.setFormat(mainContext->format());
context.setShareContext(mainContext);
context.create();
context.makeCurrent(&surface);
gl->GetInternalformativ(GL_TEXTURE_2D, GL_RG8, GL_NUM_VIRTUAL_PAGE_SIZES_ARB, sizeof(GLint), &numPageSizes);
std::vector<GLint> pageSizesRG8X(numPageSizes);
std::vector<GLint> pageSizesRG8Y(numPageSizes);
std::vector<GLint> pageSizesRG8Z(numPageSizes);
gl->GetInternalformativ(GL_TEXTURE_2D, GL_RG8, GL_VIRTUAL_PAGE_SIZE_X_ARB, numPageSizes * sizeof(GLint), pageSizesRG8X.data());
gl->GetInternalformativ(GL_TEXTURE_2D, GL_RG8, GL_VIRTUAL_PAGE_SIZE_Y_ARB, numPageSizes * sizeof(GLint), pageSizesRG8Y.data());
gl->GetInternalformativ(GL_TEXTURE_2D, GL_RG8, GL_VIRTUAL_PAGE_SIZE_Z_ARB, numPageSizes * sizeof(GLint), pageSizesRG8Z.data());
qDebug() << "RG8" << numPageSizes;
for (int i = 0; i < numPageSizes; i++)
qDebug() << pageSizesRG8X[i] << pageSizesRG8Y[i] << pageSizesRG8Z[i];
gl = std::make_unique<GladGLContext>();
if (!gladLoadGLContext(gl.get(), [](const char* name) { return (GLADapiproc)QOpenGLContext::currentContext()->getProcAddress(name); }))
qCritical() << "Failed to initialize GLAD";
pageSize = std::max(pageSizesRG8X[0], pageSizesRG8Y[0]);
qDebug() << "pageSize:" << pageSize;
GLint numPageSizes;
// Figure out how many page sizes are available for a 2D texture
gl->GetInternalformativ(GL_TEXTURE_2D, GL_RGBA8, GL_NUM_VIRTUAL_PAGE_SIZES_ARB, sizeof(GLint), &numPageSizes);
std::vector<GLint> pageSizesX(numPageSizes);
std::vector<GLint> pageSizesY(numPageSizes);
std::vector<GLint> pageSizesZ(numPageSizes);
gl->GetInternalformativ(GL_TEXTURE_2D, GL_RGBA8, GL_VIRTUAL_PAGE_SIZE_X_ARB, numPageSizes * sizeof(GLint), pageSizesX.data());
gl->GetInternalformativ(GL_TEXTURE_2D, GL_RGBA8, GL_VIRTUAL_PAGE_SIZE_Y_ARB, numPageSizes * sizeof(GLint), pageSizesY.data());
gl->GetInternalformativ(GL_TEXTURE_2D, GL_RGBA8, GL_VIRTUAL_PAGE_SIZE_Z_ARB, numPageSizes * sizeof(GLint), pageSizesZ.data());
qDebug() << "RGBA8" << numPageSizes;
for (int i = 0; i < numPageSizes; i++)
qDebug() << pageSizesX[i] << pageSizesY[i] << pageSizesZ[i];
if (!program.addShaderFromSourceFile(QOpenGLShader::Compute, ":/Shaders/painting.comp"))
qDebug() << "ERROR:" << program.log();
if (!program.link())
qDebug() << "ERROR:" << program.log();
gl->GetInternalformativ(GL_TEXTURE_2D, GL_RG8, GL_NUM_VIRTUAL_PAGE_SIZES_ARB, sizeof(GLint), &numPageSizes);
std::vector<GLint> pageSizesRG8X(numPageSizes);
std::vector<GLint> pageSizesRG8Y(numPageSizes);
std::vector<GLint> pageSizesRG8Z(numPageSizes);
gl->GetInternalformativ(GL_TEXTURE_2D, GL_RG8, GL_VIRTUAL_PAGE_SIZE_X_ARB, numPageSizes * sizeof(GLint), pageSizesRG8X.data());
gl->GetInternalformativ(GL_TEXTURE_2D, GL_RG8, GL_VIRTUAL_PAGE_SIZE_Y_ARB, numPageSizes * sizeof(GLint), pageSizesRG8Y.data());
gl->GetInternalformativ(GL_TEXTURE_2D, GL_RG8, GL_VIRTUAL_PAGE_SIZE_Z_ARB, numPageSizes * sizeof(GLint), pageSizesRG8Z.data());
qDebug() << "RG8" << numPageSizes;
for (int i = 0; i < numPageSizes; i++)
qDebug() << pageSizesRG8X[i] << pageSizesRG8Y[i] << pageSizesRG8Z[i];
pageSize = std::max(pageSizesRG8X[0], pageSizesRG8Y[0]);
qDebug() << "pageSize:" << pageSize;
if (!program.addShaderFromSourceFile(QOpenGLShader::Compute, ":/Shaders/painting.comp"))
qDebug() << "ERROR:" << program.log();
if (!program.link())
qDebug() << "ERROR:" << program.log();
initialized = true;
GLuint pageLoadTimeQuery;
gl->GenQueries(1, &pageLoadTimeQuery);
while (true)
{
if (needUpdate)
{
needUpdate = false;
auto& pageIds = pageIdsBuffer[currentBuffer];
pageIdBufferMutex.lock();
currentBuffer = 1 - currentBuffer;
pageIdBufferMutex.unlock();
gl->BeginQuery(GL_TIME_ELAPSED, pageLoadTimeQuery);
updatePages(pageIds);
gl->EndQuery(GL_TIME_ELAPSED);
GLuint duration;
gl->GetQueryObjectuiv(pageLoadTimeQuery, GL_QUERY_RESULT, &duration);
//qDebug() << duration;
pageLoadDuration += duration;
}
}
});
while (!initialized)
std::this_thread::yield();
mainContext->makeCurrent(mainSurface);
}
@ -53,30 +101,30 @@ std::uint16_t Renderer::VirtualTextureManager::createVirtualTexture(Painting pai
qDebug() << "levels:" << levels;
GLuint textures[2];
gl->CreateTextures(GL_TEXTURE_2D, 2, textures);
glMain->CreateTextures(GL_TEXTURE_2D, 2, textures);
GLuint& baseColor = textures[0];
GLuint& metallicRoughness = textures[1];
gl->TextureParameteri(baseColor, GL_TEXTURE_SPARSE_ARB, GL_TRUE);
gl->TextureParameteri(baseColor, GL_TEXTURE_BASE_LEVEL, 0);
gl->TextureParameteri(baseColor, GL_TEXTURE_MAX_LEVEL, levels - 1);
gl->TextureParameteri(baseColor, GL_TEXTURE_WRAP_S, GL_REPEAT);
gl->TextureParameteri(baseColor, GL_TEXTURE_WRAP_T, GL_REPEAT);
gl->TextureParameteri(baseColor, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
gl->TextureParameteri(baseColor, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gl->TextureStorage2D(baseColor, levels, GL_RGBA8, GLsizei(textureSize), GLsizei(textureSize));
glMain->TextureParameteri(baseColor, GL_TEXTURE_SPARSE_ARB, GL_TRUE);
glMain->TextureParameteri(baseColor, GL_TEXTURE_BASE_LEVEL, 0);
glMain->TextureParameteri(baseColor, GL_TEXTURE_MAX_LEVEL, levels - 1);
glMain->TextureParameteri(baseColor, GL_TEXTURE_WRAP_S, GL_REPEAT);
glMain->TextureParameteri(baseColor, GL_TEXTURE_WRAP_T, GL_REPEAT);
glMain->TextureParameteri(baseColor, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glMain->TextureParameteri(baseColor, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glMain->TextureStorage2D(baseColor, levels, GL_RGBA8, GLsizei(textureSize), GLsizei(textureSize));
gl->TextureParameteri(metallicRoughness, GL_TEXTURE_SPARSE_ARB, GL_TRUE);
gl->TextureParameteri(metallicRoughness, GL_TEXTURE_BASE_LEVEL, 0);
gl->TextureParameteri(metallicRoughness, GL_TEXTURE_MAX_LEVEL, levels - 1);
gl->TextureParameteri(metallicRoughness, GL_TEXTURE_WRAP_S, GL_REPEAT);
gl->TextureParameteri(metallicRoughness, GL_TEXTURE_WRAP_T, GL_REPEAT);
gl->TextureParameteri(metallicRoughness, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
gl->TextureParameteri(metallicRoughness, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gl->TextureStorage2D(metallicRoughness, levels, GL_RG8, GLsizei(textureSize), GLsizei(textureSize));
glMain->TextureParameteri(metallicRoughness, GL_TEXTURE_SPARSE_ARB, GL_TRUE);
glMain->TextureParameteri(metallicRoughness, GL_TEXTURE_BASE_LEVEL, 0);
glMain->TextureParameteri(metallicRoughness, GL_TEXTURE_MAX_LEVEL, levels - 1);
glMain->TextureParameteri(metallicRoughness, GL_TEXTURE_WRAP_S, GL_REPEAT);
glMain->TextureParameteri(metallicRoughness, GL_TEXTURE_WRAP_T, GL_REPEAT);
glMain->TextureParameteri(metallicRoughness, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glMain->TextureParameteri(metallicRoughness, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glMain->TextureStorage2D(metallicRoughness, levels, GL_RG8, GLsizei(textureSize), GLsizei(textureSize));
for (int i = 0; i < 5; i++)
gl->BindBufferBase(GL_SHADER_STORAGE_BUFFER, i, painting.buffers[i]);
glMain->BindBufferBase(GL_SHADER_STORAGE_BUFFER, i, painting.buffers[i]);
for (auto level = levels - 1; level < levels; ++level)
{
@ -84,20 +132,20 @@ std::uint16_t Renderer::VirtualTextureManager::createVirtualTexture(Painting pai
for (GLsizei j = 0; j < levelSize / pageSize; ++j)
for (GLsizei i = 0; i < levelSize / pageSize; ++i)
{
gl->TexturePageCommitmentEXT(baseColor, static_cast<GLint>(level),
glMain->TexturePageCommitmentEXT(baseColor, static_cast<GLint>(level),
static_cast<GLsizei>(pageSize) * i, static_cast<GLsizei>(pageSize) * j, 0,
static_cast<GLsizei>(pageSize), static_cast<GLsizei>(pageSize), 1,
GL_TRUE);
gl->TexturePageCommitmentEXT(metallicRoughness, static_cast<GLint>(level),
glMain->TexturePageCommitmentEXT(metallicRoughness, static_cast<GLint>(level),
static_cast<GLsizei>(pageSize) * i, static_cast<GLsizei>(pageSize) * j, 0,
static_cast<GLsizei>(pageSize), static_cast<GLsizei>(pageSize), 1,
GL_TRUE);
program.bind();
gl->Uniform2i(gl->GetUniformLocation(program.programId(), "pixelOffset"), static_cast<GLsizei>(pageSize) * i, static_cast<GLsizei>(pageSize) * j);
gl->BindImageTexture(0, baseColor, level, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);
gl->BindImageTexture(1, metallicRoughness, level, GL_FALSE, 0, GL_READ_WRITE, GL_RG8);
gl->DispatchCompute(pageSize / 8, pageSize / 8, 1);
glMain->Uniform2i(gl->GetUniformLocation(program.programId(), "pixelOffset"), static_cast<GLsizei>(pageSize) * i, static_cast<GLsizei>(pageSize) * j);
glMain->BindImageTexture(0, baseColor, level, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);
glMain->BindImageTexture(1, metallicRoughness, level, GL_FALSE, 0, GL_READ_WRITE, GL_RG8);
glMain->DispatchCompute(pageSize / 8, pageSize / 8, 1);
program.release();
}
@ -111,12 +159,22 @@ Renderer::PaintingHandle& Renderer::VirtualTextureManager::getPaintingHandle(std
return paintings[id - 1];
}
void Renderer::VirtualTextureManager::tryUpdatePages(const std::vector<glm::u16vec2>& pageIds)
{
pageIdBufferMutex.lock();
pageIdsBuffer[currentBuffer] = pageIds;
pageIdBufferMutex.unlock();
needUpdate = true;
}
void Renderer::VirtualTextureManager::pageCommitmentById(const glm::u16vec2& pageId, GLboolean commit)
{
auto& painting = getPaintingHandle(pageId.x >> 4);
GLint level = pageId.x & 0b1111;
glm::ivec2 page(pageId.y & 0b11111111, pageId.y >> 8);
qDebug() << commit << level << page.x << page.y;
//qDebug() << commit << level << page.x << page.y;
commitMutex.lock();
gl->TexturePageCommitmentEXT(painting.baseColor, level,
static_cast<GLsizei>(pageSize) * page.x, static_cast<GLsizei>(pageSize) * page.y, 0,
static_cast<GLsizei>(pageSize), static_cast<GLsizei>(pageSize), 1,
@ -129,12 +187,16 @@ void Renderer::VirtualTextureManager::pageCommitmentById(const glm::u16vec2& pag
if (commit)
{
program.bind();
for (int i = 0; i < 5; i++)
gl->BindBufferBase(GL_SHADER_STORAGE_BUFFER, i, painting.buffers[i]);
gl->Uniform2i(gl->GetUniformLocation(program.programId(), "pixelOffset"), static_cast<GLsizei>(pageSize) * page.x, static_cast<GLsizei>(pageSize) * page.y);
gl->BindImageTexture(0, painting.baseColor, level, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);
gl->BindImageTexture(1, painting.metallicRoughness, level, GL_FALSE, 0, GL_READ_WRITE, GL_RG8);
gl->DispatchCompute(pageSize / 8, pageSize / 8, 1);
program.release();
}
gl->Finish();
commitMutex.unlock();
}
void Renderer::VirtualTextureManager::updatePages(const std::vector<glm::u16vec2>& pageIds)
@ -158,7 +220,6 @@ void Renderer::VirtualTextureManager::updatePages(const std::vector<glm::u16vec2
if (success)
{
pageCommitmentById(pageId, GL_TRUE);
}
else
iter->second = lifeTime;

View File

@ -2,6 +2,10 @@
#include "Painting/Painting.h"
#include <QOpenGLShaderProgram>
#include <unordered_map>
#include <thread>
#include <atomic>
#include <mutex>
#include <QOffscreenSurface>
struct GladGLContext;
@ -17,7 +21,7 @@ namespace Renderer
class VirtualTextureManager
{
public:
VirtualTextureManager(GladGLContext* gl);
VirtualTextureManager(GladGLContext* glMain);
/**
* @brief
@ -26,9 +30,17 @@ namespace Renderer
*/
std::uint16_t createVirtualTexture(Painting painting);
PaintingHandle& getPaintingHandle(std::uint16_t id);
void updatePages(const std::vector<glm::u16vec2>& pageIds);
void tryUpdatePages(const std::vector<glm::u16vec2>& pageIds);
std::atomic<bool> initialized = false;
std::atomic<bool> needUpdate = false;
std::atomic<GLuint> pageLoadDuration = 0;
std::mutex commitMutex;
private:
GladGLContext* gl;
std::jthread thread;
QOffscreenSurface surface;
std::unique_ptr<GladGLContext> gl;
GladGLContext* glMain;
static constexpr GLsizei textureSize = 16384;
static constexpr int lifeTime = 64;
GLint pageSize;
@ -42,9 +54,11 @@ namespace Renderer
return ((std::size_t)v.y << 16) + v.x;
}
};
std::unordered_map<glm::u16vec2, int, u16vec2Hash> loadedPages;
std::vector<glm::u16vec2> pageIdsBuffer[2];
int currentBuffer = 0;
void updatePages(const std::vector<glm::u16vec2>& pageIds);
void pageCommitmentById(const glm::u16vec2& pageId, GLboolean commit);
};
}

View File

@ -3,6 +3,8 @@
#include <QtWidgets/QApplication>
#include "ElementRendererTest.h"
#include "Renderer/Painting/ElementStyle.h"
#include <qtemporaryfile.h>
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace Renderer;
@ -12,6 +14,12 @@ namespace UnitTest
TEST_CLASS(ElementRendererStokeTypeTest)
{
public:
TEST_METHOD(TestFile)
{
QFile file("D:\\BigC2022\\temp\\ArchitectureColoredPainting\\README.md");
Logger::WriteMessage(file.open(QIODevice::ReadOnly)? "True":"False");
}
TEST_METHOD(TestBothSidesRound)
{
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);