- moved most of the OpenGL backend to 'common'.
A few things are yet to do, because they still need some changes.
This commit is contained in:
parent
763e9e0f35
commit
02832297ff
26 changed files with 216 additions and 220 deletions
|
|
@ -1,266 +0,0 @@
|
|||
/*
|
||||
** Postprocessing framework
|
||||
** Copyright (c) 2016-2020 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "gl_system.h"
|
||||
#include "m_png.h"
|
||||
#include "gl/system/gl_buffers.h"
|
||||
#include "gl/system/gl_framebuffer.h"
|
||||
#include "gl/system/gl_debug.h"
|
||||
#include "gl/renderer/gl_renderbuffers.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/renderer/gl_postprocessstate.h"
|
||||
#include "gl/shaders/gl_shaderprogram.h"
|
||||
#include "hwrenderer/postprocessing/hw_postprocess.h"
|
||||
#include "hwrenderer/postprocessing/hw_postprocess_cvars.h"
|
||||
#include "flatvertices.h"
|
||||
#include "r_videoscale.h"
|
||||
#include "v_video.h"
|
||||
#include "templates.h"
|
||||
#include "hw_vrmodes.h"
|
||||
|
||||
extern bool vid_hdr_active;
|
||||
|
||||
CVAR(Int, gl_dither_bpc, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
|
||||
|
||||
namespace OpenGLRenderer
|
||||
{
|
||||
|
||||
|
||||
void FGLRenderer::RenderScreenQuad()
|
||||
{
|
||||
auto buffer = static_cast<GLVertexBuffer *>(screen->mVertexData->GetBufferObjects().first);
|
||||
buffer->Bind(nullptr);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, FFlatVertexBuffer::PRESENT_INDEX, 4);
|
||||
}
|
||||
|
||||
void FGLRenderer::PostProcessScene(int fixedcm, const std::function<void()> &afterBloomDrawEndScene2D)
|
||||
{
|
||||
int sceneWidth = mBuffers->GetSceneWidth();
|
||||
int sceneHeight = mBuffers->GetSceneHeight();
|
||||
|
||||
GLPPRenderState renderstate(mBuffers);
|
||||
|
||||
hw_postprocess.Pass1(&renderstate, fixedcm, sceneWidth, sceneHeight);
|
||||
mBuffers->BindCurrentFB();
|
||||
if (afterBloomDrawEndScene2D) afterBloomDrawEndScene2D();
|
||||
hw_postprocess.Pass2(&renderstate, fixedcm, sceneWidth, sceneHeight);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Adds ambient occlusion to the scene
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FGLRenderer::AmbientOccludeScene(float m5)
|
||||
{
|
||||
int sceneWidth = mBuffers->GetSceneWidth();
|
||||
int sceneHeight = mBuffers->GetSceneHeight();
|
||||
|
||||
GLPPRenderState renderstate(mBuffers);
|
||||
hw_postprocess.ssao.Render(&renderstate, m5, sceneWidth, sceneHeight);
|
||||
}
|
||||
|
||||
void FGLRenderer::BlurScene(float gameinfobluramount)
|
||||
{
|
||||
int sceneWidth = mBuffers->GetSceneWidth();
|
||||
int sceneHeight = mBuffers->GetSceneHeight();
|
||||
|
||||
GLPPRenderState renderstate(mBuffers);
|
||||
|
||||
auto vrmode = VRMode::GetVRMode(true);
|
||||
int eyeCount = vrmode->mEyeCount;
|
||||
for (int i = 0; i < eyeCount; ++i)
|
||||
{
|
||||
hw_postprocess.bloom.RenderBlur(&renderstate, sceneWidth, sceneHeight, gameinfobluramount);
|
||||
if (eyeCount - i > 1) mBuffers->NextEye(eyeCount);
|
||||
}
|
||||
}
|
||||
|
||||
void FGLRenderer::ClearTonemapPalette()
|
||||
{
|
||||
hw_postprocess.tonemap.ClearTonemapPalette();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Copies the rendered screen to its final destination
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FGLRenderer::Flush()
|
||||
{
|
||||
auto vrmode = VRMode::GetVRMode(true);
|
||||
if (vrmode->mEyeCount == 1)
|
||||
{
|
||||
CopyToBackbuffer(nullptr, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Render 2D to eye textures
|
||||
int eyeCount = vrmode->mEyeCount;
|
||||
for (int eye_ix = 0; eye_ix < eyeCount; ++eye_ix)
|
||||
{
|
||||
screen->Draw2D();
|
||||
if (eyeCount - eye_ix > 1)
|
||||
mBuffers->NextEye(eyeCount);
|
||||
}
|
||||
screen->Clear2D();
|
||||
|
||||
FGLPostProcessState savedState;
|
||||
FGLDebug::PushGroup("PresentEyes");
|
||||
// Note: This here is the ONLY place in the entire engine where the OpenGL dependent parts of the Stereo3D code need to be dealt with.
|
||||
// There's absolutely no need to create a overly complex class hierarchy for just this.
|
||||
PresentStereo();
|
||||
FGLDebug::PopGroup();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Gamma correct while copying to frame buffer
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FGLRenderer::CopyToBackbuffer(const IntRect *bounds, bool applyGamma)
|
||||
{
|
||||
screen->Draw2D(); // draw all pending 2D stuff before copying the buffer
|
||||
screen->Clear2D();
|
||||
|
||||
GLPPRenderState renderstate(mBuffers);
|
||||
hw_postprocess.customShaders.Run(&renderstate, "screen");
|
||||
|
||||
FGLDebug::PushGroup("CopyToBackbuffer");
|
||||
FGLPostProcessState savedState;
|
||||
savedState.SaveTextureBindings(2);
|
||||
mBuffers->BindOutputFB();
|
||||
|
||||
IntRect box;
|
||||
if (bounds)
|
||||
{
|
||||
box = *bounds;
|
||||
}
|
||||
else
|
||||
{
|
||||
ClearBorders();
|
||||
box = screen->mOutputLetterbox;
|
||||
}
|
||||
|
||||
mBuffers->BindCurrentTexture(0);
|
||||
DrawPresentTexture(box, applyGamma);
|
||||
FGLDebug::PopGroup();
|
||||
}
|
||||
|
||||
void FGLRenderer::DrawPresentTexture(const IntRect &box, bool applyGamma)
|
||||
{
|
||||
glViewport(box.left, box.top, box.width, box.height);
|
||||
|
||||
mBuffers->BindDitherTexture(1);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
if (ViewportLinearScale())
|
||||
{
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
}
|
||||
else
|
||||
{
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
}
|
||||
|
||||
mPresentShader->Bind();
|
||||
if (!applyGamma || framebuffer->IsHWGammaActive())
|
||||
{
|
||||
mPresentShader->Uniforms->InvGamma = 1.0f;
|
||||
mPresentShader->Uniforms->Contrast = 1.0f;
|
||||
mPresentShader->Uniforms->Brightness = 0.0f;
|
||||
mPresentShader->Uniforms->Saturation = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
mPresentShader->Uniforms->InvGamma = 1.0f / clamp<float>(vid_gamma, 0.1f, 4.f);
|
||||
mPresentShader->Uniforms->Contrast = clamp<float>(vid_contrast, 0.1f, 3.f);
|
||||
mPresentShader->Uniforms->Brightness = clamp<float>(vid_brightness, -0.8f, 0.8f);
|
||||
mPresentShader->Uniforms->Saturation = clamp<float>(vid_saturation, -15.0f, 15.f);
|
||||
mPresentShader->Uniforms->GrayFormula = static_cast<int>(gl_satformula);
|
||||
}
|
||||
if (vid_hdr_active && framebuffer->IsFullscreen())
|
||||
{
|
||||
// Full screen exclusive mode treats a rgba16f frame buffer as linear.
|
||||
// It probably will eventually in desktop mode too, but the DWM doesn't seem to support that.
|
||||
mPresentShader->Uniforms->HdrMode = 1;
|
||||
mPresentShader->Uniforms->ColorScale = (gl_dither_bpc == -1) ? 1023.0f : (float)((1 << gl_dither_bpc) - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
mPresentShader->Uniforms->HdrMode = 0;
|
||||
mPresentShader->Uniforms->ColorScale = (gl_dither_bpc == -1) ? 255.0f : (float)((1 << gl_dither_bpc) - 1);
|
||||
}
|
||||
mPresentShader->Uniforms->Scale = { screen->mScreenViewport.width / (float)mBuffers->GetWidth(), screen->mScreenViewport.height / (float)mBuffers->GetHeight() };
|
||||
mPresentShader->Uniforms->Offset = { 0.0f, 0.0f };
|
||||
mPresentShader->Uniforms.SetData();
|
||||
static_cast<GLDataBuffer*>(mPresentShader->Uniforms.GetBuffer())->BindBase();
|
||||
RenderScreenQuad();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Fills the black bars around the screen letterbox
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FGLRenderer::ClearBorders()
|
||||
{
|
||||
const auto &box = screen->mOutputLetterbox;
|
||||
|
||||
int clientWidth = framebuffer->GetClientWidth();
|
||||
int clientHeight = framebuffer->GetClientHeight();
|
||||
if (clientWidth == 0 || clientHeight == 0)
|
||||
return;
|
||||
|
||||
glViewport(0, 0, clientWidth, clientHeight);
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
if (box.top > 0)
|
||||
{
|
||||
glScissor(0, 0, clientWidth, box.top);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
if (clientHeight - box.top - box.height > 0)
|
||||
{
|
||||
glScissor(0, box.top + box.height, clientWidth, clientHeight - box.top - box.height);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
if (box.left > 0)
|
||||
{
|
||||
glScissor(0, box.top, box.left, box.height);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
if (clientWidth - box.left - box.width > 0)
|
||||
{
|
||||
glScissor(box.left + box.width, box.top, clientWidth - box.left - box.width, box.height);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,134 +0,0 @@
|
|||
/*
|
||||
** Postprocessing framework
|
||||
** Copyright (c) 2016-2020 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "templates.h"
|
||||
#include "gl_system.h"
|
||||
#include "gl_interface.h"
|
||||
#include "gl/renderer/gl_postprocessstate.h"
|
||||
|
||||
namespace OpenGLRenderer
|
||||
{
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Saves state modified by post processing shaders
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
FGLPostProcessState::FGLPostProcessState()
|
||||
{
|
||||
glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTex);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
SaveTextureBindings(1);
|
||||
|
||||
glGetBooleanv(GL_BLEND, &blendEnabled);
|
||||
glGetBooleanv(GL_SCISSOR_TEST, &scissorEnabled);
|
||||
glGetBooleanv(GL_DEPTH_TEST, &depthEnabled);
|
||||
glGetBooleanv(GL_MULTISAMPLE, &multisampleEnabled);
|
||||
glGetIntegerv(GL_CURRENT_PROGRAM, ¤tProgram);
|
||||
glGetIntegerv(GL_BLEND_EQUATION_RGB, &blendEquationRgb);
|
||||
glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &blendEquationAlpha);
|
||||
glGetIntegerv(GL_BLEND_SRC_RGB, &blendSrcRgb);
|
||||
glGetIntegerv(GL_BLEND_SRC_ALPHA, &blendSrcAlpha);
|
||||
glGetIntegerv(GL_BLEND_DST_RGB, &blendDestRgb);
|
||||
glGetIntegerv(GL_BLEND_DST_ALPHA, &blendDestAlpha);
|
||||
|
||||
glDisable(GL_MULTISAMPLE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
void FGLPostProcessState::SaveTextureBindings(unsigned int numUnits)
|
||||
{
|
||||
while (textureBinding.Size() < numUnits)
|
||||
{
|
||||
unsigned int i = textureBinding.Size();
|
||||
|
||||
GLint texture;
|
||||
glActiveTexture(GL_TEXTURE0 + i);
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &texture);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
textureBinding.Push(texture);
|
||||
|
||||
GLint sampler;
|
||||
glGetIntegerv(GL_SAMPLER_BINDING, &sampler);
|
||||
glBindSampler(i, 0);
|
||||
samplerBinding.Push(sampler);
|
||||
}
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Restores state at the end of post processing
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
FGLPostProcessState::~FGLPostProcessState()
|
||||
{
|
||||
if (blendEnabled)
|
||||
glEnable(GL_BLEND);
|
||||
else
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
if (scissorEnabled)
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
else
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
|
||||
if (depthEnabled)
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
else
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
if (multisampleEnabled)
|
||||
glEnable(GL_MULTISAMPLE);
|
||||
else
|
||||
glDisable(GL_MULTISAMPLE);
|
||||
|
||||
glBlendEquationSeparate(blendEquationRgb, blendEquationAlpha);
|
||||
glBlendFuncSeparate(blendSrcRgb, blendDestRgb, blendSrcAlpha, blendDestAlpha);
|
||||
|
||||
glUseProgram(currentProgram);
|
||||
|
||||
// Fully unbind to avoid incomplete texture warnings from Nvidia's driver when gl_debug_level 4 is active
|
||||
for (unsigned int i = 0; i < textureBinding.Size(); i++)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + i);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < samplerBinding.Size(); i++)
|
||||
{
|
||||
glBindSampler(i, samplerBinding[i]);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < textureBinding.Size(); i++)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + i);
|
||||
glBindTexture(GL_TEXTURE_2D, textureBinding[i]);
|
||||
}
|
||||
|
||||
glActiveTexture(activeTex);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
#ifndef __GL_POSTPROCESSSTATE_H
|
||||
#define __GL_POSTPROCESSSTATE_H
|
||||
|
||||
#include <string.h>
|
||||
#include "gl_interface.h"
|
||||
#include "matrix.h"
|
||||
#include "c_cvars.h"
|
||||
|
||||
namespace OpenGLRenderer
|
||||
{
|
||||
|
||||
class FGLPostProcessState
|
||||
{
|
||||
public:
|
||||
FGLPostProcessState();
|
||||
~FGLPostProcessState();
|
||||
|
||||
void SaveTextureBindings(unsigned int numUnits);
|
||||
|
||||
private:
|
||||
FGLPostProcessState(const FGLPostProcessState &) = delete;
|
||||
FGLPostProcessState &operator=(const FGLPostProcessState &) = delete;
|
||||
|
||||
GLint activeTex;
|
||||
TArray<GLint> textureBinding;
|
||||
TArray<GLint> samplerBinding;
|
||||
GLboolean blendEnabled;
|
||||
GLboolean scissorEnabled;
|
||||
GLboolean depthEnabled;
|
||||
GLboolean multisampleEnabled;
|
||||
GLint currentProgram;
|
||||
GLint blendEquationRgb;
|
||||
GLint blendEquationAlpha;
|
||||
GLint blendSrcRgb;
|
||||
GLint blendSrcAlpha;
|
||||
GLint blendDestRgb;
|
||||
GLint blendDestAlpha;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,995 +0,0 @@
|
|||
/*
|
||||
** Postprocessing framework
|
||||
** Copyright (c) 2016-2020 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "gl_system.h"
|
||||
#include "v_video.h"
|
||||
#include "gl_interface.h"
|
||||
#include "printf.h"
|
||||
#include "hw_cvars.h"
|
||||
#include "gl/system/gl_debug.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/renderer/gl_renderbuffers.h"
|
||||
#include "gl/renderer/gl_postprocessstate.h"
|
||||
#include "gl/shaders/gl_shaderprogram.h"
|
||||
#include "gl/system/gl_buffers.h"
|
||||
#include "templates.h"
|
||||
#include <random>
|
||||
|
||||
EXTERN_CVAR(Int, gl_debug_level)
|
||||
CVAR(Int, gl_multisample, 1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
|
||||
|
||||
namespace OpenGLRenderer
|
||||
{
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Initialize render buffers and textures used in rendering passes
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FGLRenderBuffers::FGLRenderBuffers()
|
||||
{
|
||||
glGetIntegerv(GL_MAX_SAMPLES, &mMaxSamples);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Free render buffer resources
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FGLRenderBuffers::~FGLRenderBuffers()
|
||||
{
|
||||
ClearScene();
|
||||
ClearPipeline();
|
||||
ClearEyeBuffers();
|
||||
ClearShadowMap();
|
||||
DeleteTexture(mDitherTexture);
|
||||
}
|
||||
|
||||
void FGLRenderBuffers::ClearScene()
|
||||
{
|
||||
DeleteFrameBuffer(mSceneFB);
|
||||
DeleteFrameBuffer(mSceneDataFB);
|
||||
if (mSceneUsesTextures)
|
||||
{
|
||||
DeleteTexture(mSceneMultisampleTex);
|
||||
DeleteTexture(mSceneFogTex);
|
||||
DeleteTexture(mSceneNormalTex);
|
||||
DeleteTexture(mSceneDepthStencilTex);
|
||||
}
|
||||
else
|
||||
{
|
||||
DeleteRenderBuffer(mSceneMultisampleBuf);
|
||||
DeleteRenderBuffer(mSceneFogBuf);
|
||||
DeleteRenderBuffer(mSceneNormalBuf);
|
||||
DeleteRenderBuffer(mSceneDepthStencilBuf);
|
||||
}
|
||||
}
|
||||
|
||||
void FGLRenderBuffers::ClearPipeline()
|
||||
{
|
||||
for (int i = 0; i < NumPipelineTextures; i++)
|
||||
{
|
||||
DeleteFrameBuffer(mPipelineFB[i]);
|
||||
DeleteTexture(mPipelineTexture[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void FGLRenderBuffers::ClearEyeBuffers()
|
||||
{
|
||||
for (auto handle : mEyeFBs)
|
||||
DeleteFrameBuffer(handle);
|
||||
|
||||
for (auto handle : mEyeTextures)
|
||||
DeleteTexture(handle);
|
||||
|
||||
mEyeTextures.Clear();
|
||||
mEyeFBs.Clear();
|
||||
}
|
||||
|
||||
void FGLRenderBuffers::DeleteTexture(PPGLTexture &tex)
|
||||
{
|
||||
if (tex.handle != 0)
|
||||
glDeleteTextures(1, &tex.handle);
|
||||
tex.handle = 0;
|
||||
}
|
||||
|
||||
void FGLRenderBuffers::DeleteRenderBuffer(PPGLRenderBuffer &buf)
|
||||
{
|
||||
if (buf.handle != 0)
|
||||
glDeleteRenderbuffers(1, &buf.handle);
|
||||
buf.handle = 0;
|
||||
}
|
||||
|
||||
void FGLRenderBuffers::DeleteFrameBuffer(PPGLFrameBuffer &fb)
|
||||
{
|
||||
if (fb.handle != 0)
|
||||
glDeleteFramebuffers(1, &fb.handle);
|
||||
fb.handle = 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Makes sure all render buffers have sizes suitable for rending at the
|
||||
// specified resolution
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderBuffers::Setup(int width, int height, int sceneWidth, int sceneHeight)
|
||||
{
|
||||
if (width <= 0 || height <= 0)
|
||||
I_FatalError("Requested invalid render buffer sizes: screen = %dx%d", width, height);
|
||||
|
||||
int samples = clamp((int)gl_multisample, 0, mMaxSamples);
|
||||
bool needsSceneTextures = (gl_ssao != 0);
|
||||
|
||||
GLint activeTex;
|
||||
GLint textureBinding;
|
||||
glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTex);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding);
|
||||
|
||||
if (width != mWidth || height != mHeight)
|
||||
CreatePipeline(width, height);
|
||||
|
||||
if (width != mWidth || height != mHeight || mSamples != samples || mSceneUsesTextures != needsSceneTextures)
|
||||
CreateScene(width, height, samples, needsSceneTextures);
|
||||
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
mSamples = samples;
|
||||
mSceneUsesTextures = needsSceneTextures;
|
||||
mSceneWidth = sceneWidth;
|
||||
mSceneHeight = sceneHeight;
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, textureBinding);
|
||||
glActiveTexture(activeTex);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
if (FailedCreate)
|
||||
{
|
||||
ClearScene();
|
||||
ClearPipeline();
|
||||
ClearEyeBuffers();
|
||||
mWidth = 0;
|
||||
mHeight = 0;
|
||||
mSamples = 0;
|
||||
mSceneWidth = 0;
|
||||
mSceneHeight = 0;
|
||||
I_FatalError("Unable to create render buffers.");
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Creates the scene buffers
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderBuffers::CreateScene(int width, int height, int samples, bool needsSceneTextures)
|
||||
{
|
||||
ClearScene();
|
||||
|
||||
if (samples > 1)
|
||||
{
|
||||
if (needsSceneTextures)
|
||||
{
|
||||
mSceneMultisampleTex = Create2DMultisampleTexture("SceneMultisample", GL_RGBA16F, width, height, samples, false);
|
||||
mSceneDepthStencilTex = Create2DMultisampleTexture("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height, samples, false);
|
||||
mSceneFogTex = Create2DMultisampleTexture("SceneFog", GL_RGBA8, width, height, samples, false);
|
||||
mSceneNormalTex = Create2DMultisampleTexture("SceneNormal", GL_RGB10_A2, width, height, samples, false);
|
||||
mSceneFB = CreateFrameBuffer("SceneFB", mSceneMultisampleTex, {}, {}, mSceneDepthStencilTex, true);
|
||||
mSceneDataFB = CreateFrameBuffer("SceneGBufferFB", mSceneMultisampleTex, mSceneFogTex, mSceneNormalTex, mSceneDepthStencilTex, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
mSceneMultisampleBuf = CreateRenderBuffer("SceneMultisample", GL_RGBA16F, width, height, samples);
|
||||
mSceneDepthStencilBuf = CreateRenderBuffer("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height, samples);
|
||||
mSceneFB = CreateFrameBuffer("SceneFB", mSceneMultisampleBuf, mSceneDepthStencilBuf);
|
||||
mSceneDataFB = CreateFrameBuffer("SceneGBufferFB", mSceneMultisampleBuf, mSceneDepthStencilBuf);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (needsSceneTextures)
|
||||
{
|
||||
mSceneDepthStencilTex = Create2DTexture("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height);
|
||||
mSceneFogTex = Create2DTexture("SceneFog", GL_RGBA8, width, height);
|
||||
mSceneNormalTex = Create2DTexture("SceneNormal", GL_RGB10_A2, width, height);
|
||||
mSceneFB = CreateFrameBuffer("SceneFB", mPipelineTexture[0], {}, {}, mSceneDepthStencilTex, false);
|
||||
mSceneDataFB = CreateFrameBuffer("SceneGBufferFB", mPipelineTexture[0], mSceneFogTex, mSceneNormalTex, mSceneDepthStencilTex, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
mSceneDepthStencilBuf = CreateRenderBuffer("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height);
|
||||
mSceneFB = CreateFrameBuffer("SceneFB", mPipelineTexture[0], mSceneDepthStencilBuf);
|
||||
mSceneDataFB = CreateFrameBuffer("SceneGBufferFB", mPipelineTexture[0], mSceneDepthStencilBuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Creates the buffers needed for post processing steps
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderBuffers::CreatePipeline(int width, int height)
|
||||
{
|
||||
ClearPipeline();
|
||||
ClearEyeBuffers();
|
||||
|
||||
for (int i = 0; i < NumPipelineTextures; i++)
|
||||
{
|
||||
mPipelineTexture[i] = Create2DTexture("PipelineTexture", GL_RGBA16F, width, height);
|
||||
mPipelineFB[i] = CreateFrameBuffer("PipelineFB", mPipelineTexture[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Creates eye buffers if needed
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderBuffers::CreateEyeBuffers(int eye)
|
||||
{
|
||||
if (mEyeFBs.Size() > unsigned(eye))
|
||||
return;
|
||||
|
||||
GLint activeTex, textureBinding, frameBufferBinding;
|
||||
glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTex);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding);
|
||||
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &frameBufferBinding);
|
||||
|
||||
while (mEyeFBs.Size() <= unsigned(eye))
|
||||
{
|
||||
PPGLTexture texture = Create2DTexture("EyeTexture", GL_RGBA16F, mWidth, mHeight);
|
||||
mEyeTextures.Push(texture);
|
||||
mEyeFBs.Push(CreateFrameBuffer("EyeFB", texture));
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, textureBinding);
|
||||
glActiveTexture(activeTex);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, frameBufferBinding);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Creates a 2D texture defaulting to linear filtering and clamp to edge
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PPGLTexture FGLRenderBuffers::Create2DTexture(const char *name, GLuint format, int width, int height, const void *data)
|
||||
{
|
||||
PPGLTexture tex;
|
||||
tex.Width = width;
|
||||
tex.Height = height;
|
||||
glGenTextures(1, &tex.handle);
|
||||
glBindTexture(GL_TEXTURE_2D, tex.handle);
|
||||
FGLDebug::LabelObject(GL_TEXTURE, tex.handle, name);
|
||||
|
||||
GLenum dataformat = 0, datatype = 0;
|
||||
switch (format)
|
||||
{
|
||||
case GL_RGBA8: dataformat = GL_RGBA; datatype = GL_UNSIGNED_BYTE; break;
|
||||
case GL_RGBA16: dataformat = GL_RGBA; datatype = GL_UNSIGNED_SHORT; break;
|
||||
case GL_RGBA16F: dataformat = GL_RGBA; datatype = GL_FLOAT; break;
|
||||
case GL_RGBA32F: dataformat = GL_RGBA; datatype = GL_FLOAT; break;
|
||||
case GL_RGBA16_SNORM: dataformat = GL_RGBA; datatype = GL_SHORT; break;
|
||||
case GL_R32F: dataformat = GL_RED; datatype = GL_FLOAT; break;
|
||||
case GL_R16F: dataformat = GL_RED; datatype = GL_FLOAT; break;
|
||||
case GL_RG32F: dataformat = GL_RG; datatype = GL_FLOAT; break;
|
||||
case GL_RG16F: dataformat = GL_RG; datatype = GL_FLOAT; break;
|
||||
case GL_RGB10_A2: dataformat = GL_RGBA; datatype = GL_UNSIGNED_INT_10_10_10_2; break;
|
||||
case GL_DEPTH_COMPONENT24: dataformat = GL_DEPTH_COMPONENT; datatype = GL_FLOAT; break;
|
||||
case GL_STENCIL_INDEX8: dataformat = GL_STENCIL_INDEX; datatype = GL_INT; break;
|
||||
case GL_DEPTH24_STENCIL8: dataformat = GL_DEPTH_STENCIL; datatype = GL_UNSIGNED_INT_24_8; break;
|
||||
default: I_FatalError("Unknown format passed to FGLRenderBuffers.Create2DTexture");
|
||||
}
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, dataformat, datatype, data);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
return tex;
|
||||
}
|
||||
|
||||
PPGLTexture FGLRenderBuffers::Create2DMultisampleTexture(const char *name, GLuint format, int width, int height, int samples, bool fixedSampleLocations)
|
||||
{
|
||||
PPGLTexture tex;
|
||||
tex.Width = width;
|
||||
tex.Height = height;
|
||||
glGenTextures(1, &tex.handle);
|
||||
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex.handle);
|
||||
FGLDebug::LabelObject(GL_TEXTURE, tex.handle, name);
|
||||
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, format, width, height, fixedSampleLocations);
|
||||
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
|
||||
return tex;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Creates a render buffer
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PPGLRenderBuffer FGLRenderBuffers::CreateRenderBuffer(const char *name, GLuint format, int width, int height)
|
||||
{
|
||||
PPGLRenderBuffer buf;
|
||||
glGenRenderbuffers(1, &buf.handle);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, buf.handle);
|
||||
FGLDebug::LabelObject(GL_RENDERBUFFER, buf.handle, name);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, format, width, height);
|
||||
return buf;
|
||||
}
|
||||
|
||||
PPGLRenderBuffer FGLRenderBuffers::CreateRenderBuffer(const char *name, GLuint format, int width, int height, int samples)
|
||||
{
|
||||
if (samples <= 1)
|
||||
return CreateRenderBuffer(name, format, width, height);
|
||||
|
||||
PPGLRenderBuffer buf;
|
||||
glGenRenderbuffers(1, &buf.handle);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, buf.handle);
|
||||
FGLDebug::LabelObject(GL_RENDERBUFFER, buf.handle, name);
|
||||
glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, format, width, height);
|
||||
return buf;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Creates a frame buffer
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PPGLFrameBuffer FGLRenderBuffers::CreateFrameBuffer(const char *name, PPGLTexture colorbuffer)
|
||||
{
|
||||
PPGLFrameBuffer fb;
|
||||
glGenFramebuffers(1, &fb.handle);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fb.handle);
|
||||
FGLDebug::LabelObject(GL_FRAMEBUFFER, fb.handle, name);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuffer.handle, 0);
|
||||
if (CheckFrameBufferCompleteness())
|
||||
ClearFrameBuffer(false, false);
|
||||
return fb;
|
||||
}
|
||||
|
||||
PPGLFrameBuffer FGLRenderBuffers::CreateFrameBuffer(const char *name, PPGLTexture colorbuffer, PPGLRenderBuffer depthstencil)
|
||||
{
|
||||
PPGLFrameBuffer fb;
|
||||
glGenFramebuffers(1, &fb.handle);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fb.handle);
|
||||
FGLDebug::LabelObject(GL_FRAMEBUFFER, fb.handle, name);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuffer.handle, 0);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthstencil.handle);
|
||||
if (CheckFrameBufferCompleteness())
|
||||
ClearFrameBuffer(true, true);
|
||||
return fb;
|
||||
}
|
||||
|
||||
PPGLFrameBuffer FGLRenderBuffers::CreateFrameBuffer(const char *name, PPGLRenderBuffer colorbuffer, PPGLRenderBuffer depthstencil)
|
||||
{
|
||||
PPGLFrameBuffer fb;
|
||||
glGenFramebuffers(1, &fb.handle);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fb.handle);
|
||||
FGLDebug::LabelObject(GL_FRAMEBUFFER, fb.handle, name);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuffer.handle);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthstencil.handle);
|
||||
if (CheckFrameBufferCompleteness())
|
||||
ClearFrameBuffer(true, true);
|
||||
return fb;
|
||||
}
|
||||
|
||||
PPGLFrameBuffer FGLRenderBuffers::CreateFrameBuffer(const char *name, PPGLTexture colorbuffer0, PPGLTexture colorbuffer1, PPGLTexture colorbuffer2, PPGLTexture depthstencil, bool multisample)
|
||||
{
|
||||
PPGLFrameBuffer fb;
|
||||
glGenFramebuffers(1, &fb.handle);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fb.handle);
|
||||
FGLDebug::LabelObject(GL_FRAMEBUFFER, fb.handle, name);
|
||||
if (multisample)
|
||||
{
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, colorbuffer0.handle, 0);
|
||||
if (colorbuffer1.handle != 0)
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D_MULTISAMPLE, colorbuffer1.handle, 0);
|
||||
if (colorbuffer2.handle != 0)
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D_MULTISAMPLE, colorbuffer2.handle, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D_MULTISAMPLE, depthstencil.handle, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuffer0.handle, 0);
|
||||
if (colorbuffer1.handle != 0)
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, colorbuffer1.handle, 0);
|
||||
if (colorbuffer2.handle != 0)
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, colorbuffer2.handle, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depthstencil.handle, 0);
|
||||
}
|
||||
if (CheckFrameBufferCompleteness())
|
||||
ClearFrameBuffer(true, true);
|
||||
return fb;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Verifies that the frame buffer setup is valid
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FGLRenderBuffers::CheckFrameBufferCompleteness()
|
||||
{
|
||||
GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (result == GL_FRAMEBUFFER_COMPLETE)
|
||||
return true;
|
||||
|
||||
bool FailedCreate = true;
|
||||
|
||||
if (gl_debug_level > 0)
|
||||
{
|
||||
FString error = "glCheckFramebufferStatus failed: ";
|
||||
switch (result)
|
||||
{
|
||||
default: error.AppendFormat("error code %d", (int)result); break;
|
||||
case GL_FRAMEBUFFER_UNDEFINED: error << "GL_FRAMEBUFFER_UNDEFINED"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: error << "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: error << "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: error << "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: error << "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER"; break;
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED: error << "GL_FRAMEBUFFER_UNSUPPORTED"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: error << "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS: error << "GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS"; break;
|
||||
}
|
||||
Printf("%s\n", error.GetChars());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Clear frame buffer to make sure it never contains uninitialized data
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderBuffers::ClearFrameBuffer(bool stencil, bool depth)
|
||||
{
|
||||
GLboolean scissorEnabled;
|
||||
GLint stencilValue;
|
||||
GLdouble depthValue;
|
||||
glGetBooleanv(GL_SCISSOR_TEST, &scissorEnabled);
|
||||
glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &stencilValue);
|
||||
glGetDoublev(GL_DEPTH_CLEAR_VALUE, &depthValue);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||
glClearDepth(0.0);
|
||||
glClearStencil(0);
|
||||
GLenum flags = GL_COLOR_BUFFER_BIT;
|
||||
if (stencil)
|
||||
flags |= GL_STENCIL_BUFFER_BIT;
|
||||
if (depth)
|
||||
flags |= GL_DEPTH_BUFFER_BIT;
|
||||
glClear(flags);
|
||||
glClearStencil(stencilValue);
|
||||
glClearDepth(depthValue);
|
||||
if (scissorEnabled)
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Resolves the multisample frame buffer by copying it to the first pipeline texture
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderBuffers::BlitSceneToTexture()
|
||||
{
|
||||
mCurrentPipelineTexture = 0;
|
||||
|
||||
if (mSamples <= 1)
|
||||
return;
|
||||
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, mSceneFB.handle);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mPipelineFB[mCurrentPipelineTexture].handle);
|
||||
glBlitFramebuffer(0, 0, mWidth, mHeight, 0, 0, mWidth, mHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
|
||||
if ((gl.flags & RFL_INVALIDATE_BUFFER) != 0)
|
||||
{
|
||||
GLenum attachments[2] = { GL_COLOR_ATTACHMENT0, GL_DEPTH_STENCIL_ATTACHMENT };
|
||||
glInvalidateFramebuffer(GL_READ_FRAMEBUFFER, 2, attachments);
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Eye textures and their frame buffers
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderBuffers::BlitToEyeTexture(int eye, bool allowInvalidate)
|
||||
{
|
||||
CreateEyeBuffers(eye);
|
||||
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, mPipelineFB[mCurrentPipelineTexture].handle);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mEyeFBs[eye].handle);
|
||||
glBlitFramebuffer(0, 0, mWidth, mHeight, 0, 0, mWidth, mHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
|
||||
if ((gl.flags & RFL_INVALIDATE_BUFFER) != 0 && allowInvalidate)
|
||||
{
|
||||
GLenum attachments[2] = { GL_COLOR_ATTACHMENT0, GL_DEPTH_STENCIL_ATTACHMENT };
|
||||
glInvalidateFramebuffer(GL_READ_FRAMEBUFFER, 2, attachments);
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
void FGLRenderBuffers::BlitFromEyeTexture(int eye)
|
||||
{
|
||||
if (mEyeFBs.Size() <= unsigned(eye)) return;
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mPipelineFB[mCurrentPipelineTexture].handle);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, mEyeFBs[eye].handle);
|
||||
glBlitFramebuffer(0, 0, mWidth, mHeight, 0, 0, mWidth, mHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
|
||||
if ((gl.flags & RFL_INVALIDATE_BUFFER) != 0)
|
||||
{
|
||||
GLenum attachments[2] = { GL_COLOR_ATTACHMENT0, GL_DEPTH_STENCIL_ATTACHMENT };
|
||||
glInvalidateFramebuffer(GL_READ_FRAMEBUFFER, 2, attachments);
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
void FGLRenderBuffers::BindEyeTexture(int eye, int texunit)
|
||||
{
|
||||
CreateEyeBuffers(eye);
|
||||
glActiveTexture(GL_TEXTURE0 + texunit);
|
||||
glBindTexture(GL_TEXTURE_2D, mEyeTextures[eye].handle);
|
||||
}
|
||||
|
||||
void FGLRenderBuffers::BindDitherTexture(int texunit)
|
||||
{
|
||||
if (!mDitherTexture)
|
||||
{
|
||||
static const float data[64] =
|
||||
{
|
||||
.0078125, .2578125, .1328125, .3828125, .0234375, .2734375, .1484375, .3984375,
|
||||
.7578125, .5078125, .8828125, .6328125, .7734375, .5234375, .8984375, .6484375,
|
||||
.0703125, .3203125, .1953125, .4453125, .0859375, .3359375, .2109375, .4609375,
|
||||
.8203125, .5703125, .9453125, .6953125, .8359375, .5859375, .9609375, .7109375,
|
||||
.0390625, .2890625, .1640625, .4140625, .0546875, .3046875, .1796875, .4296875,
|
||||
.7890625, .5390625, .9140625, .6640625, .8046875, .5546875, .9296875, .6796875,
|
||||
.1015625, .3515625, .2265625, .4765625, .1171875, .3671875, .2421875, .4921875,
|
||||
.8515625, .6015625, .9765625, .7265625, .8671875, .6171875, .9921875, .7421875,
|
||||
};
|
||||
|
||||
glActiveTexture(GL_TEXTURE0 + texunit);
|
||||
mDitherTexture = Create2DTexture("DitherTexture", GL_R32F, 8, 8, data);
|
||||
}
|
||||
mDitherTexture.Bind(1, GL_NEAREST, GL_REPEAT);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Shadow map texture and frame buffers
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderBuffers::BindShadowMapFB()
|
||||
{
|
||||
CreateShadowMap();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, mShadowMapFB.handle);
|
||||
}
|
||||
|
||||
void FGLRenderBuffers::BindShadowMapTexture(int texunit)
|
||||
{
|
||||
CreateShadowMap();
|
||||
glActiveTexture(GL_TEXTURE0 + texunit);
|
||||
glBindTexture(GL_TEXTURE_2D, mShadowMapTexture.handle);
|
||||
}
|
||||
|
||||
void FGLRenderBuffers::ClearShadowMap()
|
||||
{
|
||||
DeleteFrameBuffer(mShadowMapFB);
|
||||
DeleteTexture(mShadowMapTexture);
|
||||
mCurrentShadowMapSize = 0;
|
||||
}
|
||||
|
||||
void FGLRenderBuffers::CreateShadowMap()
|
||||
{
|
||||
if (mShadowMapTexture.handle != 0 && gl_shadowmap_quality == mCurrentShadowMapSize)
|
||||
return;
|
||||
|
||||
ClearShadowMap();
|
||||
|
||||
GLint activeTex, textureBinding, frameBufferBinding;
|
||||
glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTex);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding);
|
||||
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &frameBufferBinding);
|
||||
|
||||
mShadowMapTexture = Create2DTexture("ShadowMap", GL_R32F, gl_shadowmap_quality, 1024);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
mShadowMapFB = CreateFrameBuffer("ShadowMapFB", mShadowMapTexture);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, textureBinding);
|
||||
glActiveTexture(activeTex);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, frameBufferBinding);
|
||||
|
||||
mCurrentShadowMapSize = gl_shadowmap_quality;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Makes the scene frame buffer active (multisample, depth, stecil, etc.)
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderBuffers::BindSceneFB(bool sceneData)
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, sceneData ? mSceneDataFB.handle : mSceneFB.handle);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Binds the scene color texture to the specified texture unit
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderBuffers::BindSceneColorTexture(int index)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + index);
|
||||
if (mSamples > 1)
|
||||
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mSceneMultisampleTex.handle);
|
||||
else
|
||||
glBindTexture(GL_TEXTURE_2D, mPipelineTexture[0].handle);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Binds the scene fog data texture to the specified texture unit
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderBuffers::BindSceneFogTexture(int index)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + index);
|
||||
if (mSamples > 1)
|
||||
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mSceneFogTex.handle);
|
||||
else
|
||||
glBindTexture(GL_TEXTURE_2D, mSceneFogTex.handle);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Binds the scene normal data texture to the specified texture unit
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderBuffers::BindSceneNormalTexture(int index)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + index);
|
||||
if (mSamples > 1)
|
||||
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mSceneNormalTex.handle);
|
||||
else
|
||||
glBindTexture(GL_TEXTURE_2D, mSceneNormalTex.handle);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Binds the depth texture to the specified texture unit
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderBuffers::BindSceneDepthTexture(int index)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + index);
|
||||
if (mSamples > 1)
|
||||
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mSceneDepthStencilTex.handle);
|
||||
else
|
||||
glBindTexture(GL_TEXTURE_2D, mSceneDepthStencilTex.handle);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Binds the current scene/effect/hud texture to the specified texture unit
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderBuffers::BindCurrentTexture(int index, int filter, int wrap)
|
||||
{
|
||||
mPipelineTexture[mCurrentPipelineTexture].Bind(index, filter, wrap);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Makes the frame buffer for the current texture active
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderBuffers::BindCurrentFB()
|
||||
{
|
||||
mPipelineFB[mCurrentPipelineTexture].Bind();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Makes the frame buffer for the next texture active
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderBuffers::BindNextFB()
|
||||
{
|
||||
int out = (mCurrentPipelineTexture + 1) % NumPipelineTextures;
|
||||
mPipelineFB[out].Bind();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Next pipeline texture now contains the output
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderBuffers::NextTexture()
|
||||
{
|
||||
mCurrentPipelineTexture = (mCurrentPipelineTexture + 1) % NumPipelineTextures;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Makes the screen frame buffer active
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderBuffers::BindOutputFB()
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Returns true if render buffers are supported and should be used
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FGLRenderBuffers::FailedCreate = false;
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Creates or updates textures used by postprocess effects
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PPGLTextureBackend *GLPPRenderState::GetGLTexture(PPTexture *texture)
|
||||
{
|
||||
if (!texture->Backend)
|
||||
{
|
||||
FGLPostProcessState savedState;
|
||||
|
||||
auto backend = std::make_unique<PPGLTextureBackend>();
|
||||
|
||||
int glformat;
|
||||
switch (texture->Format)
|
||||
{
|
||||
default:
|
||||
case PixelFormat::Rgba8: glformat = GL_RGBA8; break;
|
||||
case PixelFormat::Rgba16f: glformat = GL_RGBA16F; break;
|
||||
case PixelFormat::R32f: glformat = GL_R32F; break;
|
||||
case PixelFormat::Rg16f: glformat = GL_RG16F; break;
|
||||
case PixelFormat::Rgba16_snorm: glformat = GL_RGBA16_SNORM; break;
|
||||
}
|
||||
|
||||
if (texture->Data)
|
||||
backend->Tex = buffers->Create2DTexture("PPTexture", glformat, texture->Width, texture->Height, texture->Data.get());
|
||||
else
|
||||
backend->Tex = buffers->Create2DTexture("PPTexture", glformat, texture->Width, texture->Height);
|
||||
|
||||
texture->Backend = std::move(backend);
|
||||
}
|
||||
return static_cast<PPGLTextureBackend*>(texture->Backend.get());
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Compile the shaders declared by post process effects
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FShaderProgram *GLPPRenderState::GetGLShader(PPShader *shader)
|
||||
{
|
||||
if (!shader->Backend)
|
||||
{
|
||||
auto glshader = std::make_unique<FShaderProgram>();
|
||||
|
||||
FString prolog;
|
||||
if (!shader->Uniforms.empty())
|
||||
prolog = UniformBlockDecl::Create("Uniforms", shader->Uniforms, POSTPROCESS_BINDINGPOINT);
|
||||
prolog += shader->Defines;
|
||||
|
||||
glshader->Compile(FShaderProgram::Vertex, shader->VertexShader, "", shader->Version);
|
||||
glshader->Compile(FShaderProgram::Fragment, shader->FragmentShader, prolog, shader->Version);
|
||||
glshader->Link(shader->FragmentShader.GetChars());
|
||||
if (!shader->Uniforms.empty())
|
||||
glshader->SetUniformBufferLocation(POSTPROCESS_BINDINGPOINT, "Uniforms");
|
||||
|
||||
shader->Backend = std::move(glshader);
|
||||
}
|
||||
return static_cast<FShaderProgram*>(shader->Backend.get());
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Renders one post process effect
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void GLPPRenderState::Draw()
|
||||
{
|
||||
FGLPostProcessState savedState;
|
||||
|
||||
// Bind input textures
|
||||
for (unsigned int index = 0; index < Textures.Size(); index++)
|
||||
{
|
||||
savedState.SaveTextureBindings(index + 1);
|
||||
|
||||
const PPTextureInput &input = Textures[index];
|
||||
int filter = (input.Filter == PPFilterMode::Nearest) ? GL_NEAREST : GL_LINEAR;
|
||||
int wrap = (input.Wrap == PPWrapMode::Clamp) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
|
||||
|
||||
switch (input.Type)
|
||||
{
|
||||
default:
|
||||
case PPTextureType::CurrentPipelineTexture:
|
||||
buffers->BindCurrentTexture(index, filter, wrap);
|
||||
break;
|
||||
|
||||
case PPTextureType::NextPipelineTexture:
|
||||
I_FatalError("PPTextureType::NextPipelineTexture not allowed as input\n");
|
||||
break;
|
||||
|
||||
case PPTextureType::PPTexture:
|
||||
GetGLTexture(input.Texture)->Tex.Bind(index, filter, wrap);
|
||||
break;
|
||||
|
||||
case PPTextureType::SceneColor:
|
||||
buffers->BindSceneColorTexture(index);
|
||||
break;
|
||||
|
||||
case PPTextureType::SceneFog:
|
||||
buffers->BindSceneFogTexture(index);
|
||||
break;
|
||||
|
||||
case PPTextureType::SceneNormal:
|
||||
buffers->BindSceneNormalTexture(index);
|
||||
break;
|
||||
|
||||
case PPTextureType::SceneDepth:
|
||||
buffers->BindSceneDepthTexture(index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Set render target
|
||||
switch (Output.Type)
|
||||
{
|
||||
default:
|
||||
I_FatalError("Unsupported postprocess output type\n");
|
||||
break;
|
||||
|
||||
case PPTextureType::CurrentPipelineTexture:
|
||||
buffers->BindCurrentFB();
|
||||
break;
|
||||
|
||||
case PPTextureType::NextPipelineTexture:
|
||||
buffers->BindNextFB();
|
||||
break;
|
||||
|
||||
case PPTextureType::PPTexture:
|
||||
if (GetGLTexture(Output.Texture)->FB)
|
||||
GetGLTexture(Output.Texture)->FB.Bind();
|
||||
else
|
||||
GetGLTexture(Output.Texture)->FB = buffers->CreateFrameBuffer("PPTextureFB"/*Output.Texture.GetChars()*/, GetGLTexture(Output.Texture)->Tex);
|
||||
break;
|
||||
|
||||
case PPTextureType::SceneColor:
|
||||
buffers->BindSceneFB(false);
|
||||
break;
|
||||
}
|
||||
|
||||
// Set blend mode
|
||||
if (BlendMode.BlendOp == STYLEOP_Add && BlendMode.SrcAlpha == STYLEALPHA_One && BlendMode.DestAlpha == STYLEALPHA_Zero && BlendMode.Flags == 0)
|
||||
{
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
else
|
||||
{
|
||||
// To do: support all the modes
|
||||
glEnable(GL_BLEND);
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
if (BlendMode.SrcAlpha == STYLEALPHA_One && BlendMode.DestAlpha == STYLEALPHA_One)
|
||||
glBlendFunc(GL_ONE, GL_ONE);
|
||||
else
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
// Setup viewport
|
||||
glViewport(Viewport.left, Viewport.top, Viewport.width, Viewport.height);
|
||||
|
||||
auto shader = GetGLShader(Shader);
|
||||
|
||||
// Set uniforms
|
||||
if (Uniforms.Data.Size() > 0)
|
||||
{
|
||||
if (!shader->Uniforms)
|
||||
shader->Uniforms.reset(screen->CreateDataBuffer(POSTPROCESS_BINDINGPOINT, false, false));
|
||||
shader->Uniforms->SetData(Uniforms.Data.Size(), Uniforms.Data.Data());
|
||||
static_cast<GLDataBuffer*>(shader->Uniforms.get())->BindBase();
|
||||
}
|
||||
|
||||
// Set shader
|
||||
shader->Bind();
|
||||
|
||||
// Draw the screen quad
|
||||
GLRenderer->RenderScreenQuad();
|
||||
|
||||
// Advance to next PP texture if our output was sent there
|
||||
if (Output.Type == PPTextureType::NextPipelineTexture)
|
||||
buffers->NextTexture();
|
||||
|
||||
glViewport(screen->mScreenViewport.left, screen->mScreenViewport.top, screen->mScreenViewport.width, screen->mScreenViewport.height);
|
||||
}
|
||||
|
||||
void GLPPRenderState::PushGroup(const FString &name)
|
||||
{
|
||||
FGLDebug::PushGroup(name.GetChars());
|
||||
}
|
||||
|
||||
void GLPPRenderState::PopGroup()
|
||||
{
|
||||
FGLDebug::PopGroup();
|
||||
}
|
||||
|
||||
|
||||
// Store the current stereo 3D eye buffer, and Load the next one
|
||||
|
||||
int FGLRenderBuffers::NextEye(int eyeCount)
|
||||
{
|
||||
int nextEye = (mCurrentEye + 1) % eyeCount;
|
||||
if (nextEye == mCurrentEye) return mCurrentEye;
|
||||
BlitToEyeTexture(mCurrentEye);
|
||||
mCurrentEye = nextEye;
|
||||
BlitFromEyeTexture(mCurrentEye);
|
||||
return mCurrentEye;
|
||||
}
|
||||
|
||||
} // namespace OpenGLRenderer
|
||||
|
|
@ -1,211 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "hwrenderer/postprocessing/hw_postprocess.h"
|
||||
|
||||
namespace OpenGLRenderer
|
||||
{
|
||||
|
||||
class FGLRenderBuffers;
|
||||
|
||||
class PPGLTexture
|
||||
{
|
||||
public:
|
||||
void Bind(int index, int filter = GL_NEAREST, int wrap = GL_CLAMP_TO_EDGE)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + index);
|
||||
glBindTexture(GL_TEXTURE_2D, handle);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap);
|
||||
}
|
||||
|
||||
int Width = -1;
|
||||
int Height = -1;
|
||||
|
||||
explicit operator bool() const { return handle != 0; }
|
||||
|
||||
private:
|
||||
GLuint handle = 0;
|
||||
|
||||
friend class FGLRenderBuffers;
|
||||
friend class PPGLTextureBackend;
|
||||
};
|
||||
|
||||
class PPGLFrameBuffer
|
||||
{
|
||||
public:
|
||||
void Bind()
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, handle);
|
||||
}
|
||||
|
||||
explicit operator bool() const { return handle != 0; }
|
||||
|
||||
private:
|
||||
GLuint handle = 0;
|
||||
|
||||
friend class FGLRenderBuffers;
|
||||
friend class PPGLTextureBackend;
|
||||
};
|
||||
|
||||
class PPGLRenderBuffer
|
||||
{
|
||||
private:
|
||||
GLuint handle = 0;
|
||||
|
||||
explicit operator bool() const { return handle != 0; }
|
||||
|
||||
friend class FGLRenderBuffers;
|
||||
};
|
||||
|
||||
class PPGLTextureBackend : public PPTextureBackend
|
||||
{
|
||||
public:
|
||||
~PPGLTextureBackend()
|
||||
{
|
||||
if (Tex.handle != 0)
|
||||
{
|
||||
glDeleteTextures(1, &Tex.handle);
|
||||
Tex.handle = 0;
|
||||
}
|
||||
if (FB.handle != 0)
|
||||
{
|
||||
glDeleteFramebuffers(1, &FB.handle);
|
||||
FB.handle = 0;
|
||||
}
|
||||
}
|
||||
|
||||
PPGLTexture Tex;
|
||||
PPGLFrameBuffer FB;
|
||||
};
|
||||
|
||||
class FShaderProgram;
|
||||
|
||||
class GLPPRenderState : public PPRenderState
|
||||
{
|
||||
public:
|
||||
GLPPRenderState(FGLRenderBuffers *buffers) : buffers(buffers) { }
|
||||
|
||||
void PushGroup(const FString &name) override;
|
||||
void PopGroup() override;
|
||||
void Draw() override;
|
||||
|
||||
private:
|
||||
PPGLTextureBackend *GetGLTexture(PPTexture *texture);
|
||||
FShaderProgram *GetGLShader(PPShader *shader);
|
||||
|
||||
FGLRenderBuffers *buffers;
|
||||
};
|
||||
|
||||
class FGLRenderBuffers
|
||||
{
|
||||
public:
|
||||
FGLRenderBuffers();
|
||||
~FGLRenderBuffers();
|
||||
|
||||
void Setup(int width, int height, int sceneWidth, int sceneHeight);
|
||||
|
||||
void BindSceneFB(bool sceneData);
|
||||
void BindSceneColorTexture(int index);
|
||||
void BindSceneFogTexture(int index);
|
||||
void BindSceneNormalTexture(int index);
|
||||
void BindSceneDepthTexture(int index);
|
||||
void BlitSceneToTexture();
|
||||
|
||||
void BindCurrentTexture(int index, int filter = GL_NEAREST, int wrap = GL_CLAMP_TO_EDGE);
|
||||
void BindCurrentFB();
|
||||
void BindNextFB();
|
||||
void NextTexture();
|
||||
|
||||
PPGLFrameBuffer GetCurrentFB() const { return mPipelineFB[mCurrentPipelineTexture]; }
|
||||
|
||||
void BindOutputFB();
|
||||
|
||||
void BlitToEyeTexture(int eye, bool allowInvalidate=true);
|
||||
void BlitFromEyeTexture(int eye);
|
||||
void BindEyeTexture(int eye, int texunit);
|
||||
int NextEye(int eyeCount);
|
||||
int & CurrentEye() { return mCurrentEye; }
|
||||
|
||||
void BindDitherTexture(int texunit);
|
||||
|
||||
void BindShadowMapFB();
|
||||
void BindShadowMapTexture(int index);
|
||||
|
||||
int GetWidth() const { return mWidth; }
|
||||
int GetHeight() const { return mHeight; }
|
||||
|
||||
int GetSceneWidth() const { return mSceneWidth; }
|
||||
int GetSceneHeight() const { return mSceneHeight; }
|
||||
|
||||
private:
|
||||
void ClearScene();
|
||||
void ClearPipeline();
|
||||
void ClearEyeBuffers();
|
||||
void ClearShadowMap();
|
||||
void CreateScene(int width, int height, int samples, bool needsSceneTextures);
|
||||
void CreatePipeline(int width, int height);
|
||||
void CreateEyeBuffers(int eye);
|
||||
void CreateShadowMap();
|
||||
|
||||
PPGLTexture Create2DTexture(const char *name, GLuint format, int width, int height, const void *data = nullptr);
|
||||
PPGLTexture Create2DMultisampleTexture(const char *name, GLuint format, int width, int height, int samples, bool fixedSampleLocations);
|
||||
PPGLRenderBuffer CreateRenderBuffer(const char *name, GLuint format, int width, int height);
|
||||
PPGLRenderBuffer CreateRenderBuffer(const char *name, GLuint format, int width, int height, int samples);
|
||||
PPGLFrameBuffer CreateFrameBuffer(const char *name, PPGLTexture colorbuffer);
|
||||
PPGLFrameBuffer CreateFrameBuffer(const char *name, PPGLTexture colorbuffer, PPGLRenderBuffer depthstencil);
|
||||
PPGLFrameBuffer CreateFrameBuffer(const char *name, PPGLRenderBuffer colorbuffer, PPGLRenderBuffer depthstencil);
|
||||
PPGLFrameBuffer CreateFrameBuffer(const char *name, PPGLTexture colorbuffer0, PPGLTexture colorbuffer1, PPGLTexture colorbuffer2, PPGLTexture depthstencil, bool multisample);
|
||||
bool CheckFrameBufferCompleteness();
|
||||
void ClearFrameBuffer(bool stencil, bool depth);
|
||||
void DeleteTexture(PPGLTexture &handle);
|
||||
void DeleteRenderBuffer(PPGLRenderBuffer &handle);
|
||||
void DeleteFrameBuffer(PPGLFrameBuffer &handle);
|
||||
|
||||
int mWidth = 0;
|
||||
int mHeight = 0;
|
||||
int mSamples = 0;
|
||||
int mMaxSamples = 0;
|
||||
int mSceneWidth = 0;
|
||||
int mSceneHeight = 0;
|
||||
|
||||
static const int NumPipelineTextures = 2;
|
||||
int mCurrentPipelineTexture = 0;
|
||||
|
||||
// Buffers for the scene
|
||||
PPGLTexture mSceneMultisampleTex;
|
||||
PPGLTexture mSceneDepthStencilTex;
|
||||
PPGLTexture mSceneFogTex;
|
||||
PPGLTexture mSceneNormalTex;
|
||||
PPGLRenderBuffer mSceneMultisampleBuf;
|
||||
PPGLRenderBuffer mSceneDepthStencilBuf;
|
||||
PPGLRenderBuffer mSceneFogBuf;
|
||||
PPGLRenderBuffer mSceneNormalBuf;
|
||||
PPGLFrameBuffer mSceneFB;
|
||||
PPGLFrameBuffer mSceneDataFB;
|
||||
bool mSceneUsesTextures = false;
|
||||
|
||||
// Effect/HUD buffers
|
||||
PPGLTexture mPipelineTexture[NumPipelineTextures];
|
||||
PPGLFrameBuffer mPipelineFB[NumPipelineTextures];
|
||||
|
||||
// Eye buffers
|
||||
TArray<PPGLTexture> mEyeTextures;
|
||||
TArray<PPGLFrameBuffer> mEyeFBs;
|
||||
int mCurrentEye = 0;
|
||||
|
||||
// Shadow map texture
|
||||
PPGLTexture mShadowMapTexture;
|
||||
PPGLFrameBuffer mShadowMapFB;
|
||||
int mCurrentShadowMapSize = 0;
|
||||
|
||||
PPGLTexture mDitherTexture;
|
||||
|
||||
static bool FailedCreate;
|
||||
|
||||
friend class GLPPRenderState;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -1,28 +1,35 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2005-2016 Christoph Oelckers
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
/*
|
||||
** gl1_renderer.cpp
|
||||
** gl_renderer.cpp
|
||||
** Renderer interface
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2005-2020 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "gl_system.h"
|
||||
|
|
@ -36,6 +43,7 @@
|
|||
#include "d_player.h"
|
||||
#include "a_dynlight.h"
|
||||
#include "cmdlib.h"
|
||||
#include "version.h"
|
||||
#include "g_game.h"
|
||||
#include "swrenderer/r_swscene.h"
|
||||
#include "hwrenderer/utility/hw_clock.h"
|
||||
|
|
@ -43,22 +51,22 @@
|
|||
#include "gl_interface.h"
|
||||
#include "gl/system/gl_framebuffer.h"
|
||||
#include "hw_cvars.h"
|
||||
#include "gl/system/gl_debug.h"
|
||||
#include "gl_debug.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/renderer/gl_renderstate.h"
|
||||
#include "gl/renderer/gl_renderbuffers.h"
|
||||
#include "gl_renderstate.h"
|
||||
#include "gl_renderbuffers.h"
|
||||
#include "gl/shaders/gl_shaderprogram.h"
|
||||
#include "hw_vrmodes.h"
|
||||
#include "flatvertices.h"
|
||||
#include "hwrenderer/scene/hw_skydome.h"
|
||||
#include "hwrenderer/scene/hw_fakeflat.h"
|
||||
#include "gl/textures/gl_samplers.h"
|
||||
#include "gl_samplers.h"
|
||||
#include "hw_lightbuffer.h"
|
||||
#include "hwrenderer/data/hw_viewpointbuffer.h"
|
||||
#include "r_videoscale.h"
|
||||
#include "r_data/models/models.h"
|
||||
#include "gl/renderer/gl_postprocessstate.h"
|
||||
#include "gl/system/gl_buffers.h"
|
||||
#include "gl_postprocessstate.h"
|
||||
#include "gl_buffers.h"
|
||||
#include "texturemanager.h"
|
||||
|
||||
EXTERN_CVAR(Int, screenblocks)
|
||||
|
|
@ -95,8 +103,6 @@ void FGLRenderer::Initialize(int width, int height)
|
|||
mShadowMapShader = new FShadowMapShader();
|
||||
|
||||
// needed for the core profile, because someone decided it was a good idea to remove the default VAO.
|
||||
glGenQueries(1, &PortalQueryObject);
|
||||
|
||||
glGenVertexArrays(1, &mVAOID);
|
||||
glBindVertexArray(mVAOID);
|
||||
FGLDebug::LabelObject(GL_VERTEX_ARRAY, mVAOID, "FGLRenderer.mVAOID");
|
||||
|
|
@ -120,8 +126,6 @@ FGLRenderer::~FGLRenderer()
|
|||
glBindVertexArray(0);
|
||||
glDeleteVertexArrays(1, &mVAOID);
|
||||
}
|
||||
if (PortalQueryObject != 0) glDeleteQueries(1, &PortalQueryObject);
|
||||
|
||||
if (mBuffers) delete mBuffers;
|
||||
if (mSaveBuffers) delete mSaveBuffers;
|
||||
if (mPresentShader) delete mPresentShader;
|
||||
|
|
@ -160,44 +164,6 @@ void FGLRenderer::EndOffscreen()
|
|||
glBindFramebuffer(GL_FRAMEBUFFER, mOldFBID);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FGLRenderer::UpdateShadowMap()
|
||||
{
|
||||
if (screen->mShadowMap.PerformUpdate())
|
||||
{
|
||||
FGLDebug::PushGroup("ShadowMap");
|
||||
|
||||
FGLPostProcessState savedState;
|
||||
|
||||
static_cast<GLDataBuffer*>(screen->mShadowMap.mLightList)->BindBase();
|
||||
static_cast<GLDataBuffer*>(screen->mShadowMap.mNodesBuffer)->BindBase();
|
||||
static_cast<GLDataBuffer*>(screen->mShadowMap.mLinesBuffer)->BindBase();
|
||||
|
||||
mBuffers->BindShadowMapFB();
|
||||
|
||||
mShadowMapShader->Bind();
|
||||
mShadowMapShader->Uniforms->ShadowmapQuality = gl_shadowmap_quality;
|
||||
mShadowMapShader->Uniforms->NodesCount = screen->mShadowMap.NodesCount();
|
||||
mShadowMapShader->Uniforms.SetData();
|
||||
static_cast<GLDataBuffer*>(mShadowMapShader->Uniforms.GetBuffer())->BindBase();
|
||||
|
||||
glViewport(0, 0, gl_shadowmap_quality, 1024);
|
||||
RenderScreenQuad();
|
||||
|
||||
const auto &viewport = screen->mScreenViewport;
|
||||
glViewport(viewport.left, viewport.top, viewport.width, viewport.height);
|
||||
|
||||
mBuffers->BindShadowMapTexture(16);
|
||||
FGLDebug::PopGroup();
|
||||
screen->mShadowMap.FinishUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
|
|
@ -207,14 +173,10 @@ void FGLRenderer::UpdateShadowMap()
|
|||
void FGLRenderer::BindToFrameBuffer(FTexture *tex)
|
||||
{
|
||||
auto BaseLayer = static_cast<FHardwareTexture*>(tex->GetHardwareTexture(0, 0));
|
||||
|
||||
if (BaseLayer == nullptr)
|
||||
{
|
||||
// must create the hardware texture first
|
||||
BaseLayer->BindOrCreate(tex, 0, 0, 0, 0);
|
||||
FHardwareTexture::Unbind(0);
|
||||
gl_RenderState.ClearLastMaterial();
|
||||
}
|
||||
// must create the hardware texture first
|
||||
BaseLayer->BindOrCreate(tex, 0, 0, 0, 0);
|
||||
FHardwareTexture::Unbind(0);
|
||||
gl_RenderState.ClearLastMaterial();
|
||||
BaseLayer->BindToFrameBuffer(tex->GetWidth(), tex->GetHeight());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
#include "vectors.h"
|
||||
#include "swrenderer/r_renderer.h"
|
||||
#include "matrix.h"
|
||||
#include "gl/renderer/gl_renderbuffers.h"
|
||||
#include "gl_renderbuffers.h"
|
||||
#include "hwrenderer/scene/hw_portal.h"
|
||||
#include "hwrenderer/dynlights/hw_shadowmap.h"
|
||||
#include <functional>
|
||||
|
|
@ -52,7 +52,6 @@ public:
|
|||
FSamplerManager *mSamplerManager = nullptr;
|
||||
unsigned int mFBID;
|
||||
unsigned int mVAOID;
|
||||
unsigned int PortalQueryObject;
|
||||
unsigned int mStencilValue = 0;
|
||||
|
||||
int mOldFBID;
|
||||
|
|
@ -89,7 +88,6 @@ public:
|
|||
|
||||
bool StartOffscreen();
|
||||
void EndOffscreen();
|
||||
void UpdateShadowMap();
|
||||
|
||||
void BindToFrameBuffer(FTexture *mat);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,586 +0,0 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2009-2016 Christoph Oelckers
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
/*
|
||||
** gl_renderstate.cpp
|
||||
** Render state maintenance
|
||||
**
|
||||
*/
|
||||
|
||||
#include "templates.h"
|
||||
#include "doomstat.h"
|
||||
#include "r_data/colormaps.h"
|
||||
#include "gl_system.h"
|
||||
#include "gl_interface.h"
|
||||
#include "hw_cvars.h"
|
||||
#include "flatvertices.h"
|
||||
#include "hwrenderer/scene/hw_skydome.h"
|
||||
#include "gl/shaders/gl_shader.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "hw_lightbuffer.h"
|
||||
#include "gl/renderer/gl_renderbuffers.h"
|
||||
#include "gl/textures/gl_hwtexture.h"
|
||||
#include "gl/system/gl_buffers.h"
|
||||
#include "hwrenderer/utility/hw_clock.h"
|
||||
#include "hwrenderer/data/hw_viewpointbuffer.h"
|
||||
|
||||
namespace OpenGLRenderer
|
||||
{
|
||||
|
||||
FGLRenderState gl_RenderState;
|
||||
|
||||
static VSMatrix identityMatrix(1);
|
||||
|
||||
static void matrixToGL(const VSMatrix &mat, int loc)
|
||||
{
|
||||
glUniformMatrix4fv(loc, 1, false, (float*)&mat);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// This only gets called once upon setup.
|
||||
// With OpenGL the state is persistent and cannot be cleared, once set up.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderState::Reset()
|
||||
{
|
||||
FRenderState::Reset();
|
||||
mVertexBuffer = mCurrentVertexBuffer = nullptr;
|
||||
mGlossiness = 0.0f;
|
||||
mSpecularLevel = 0.0f;
|
||||
mShaderTimer = 0.0f;
|
||||
|
||||
stRenderStyle = DefaultRenderStyle();
|
||||
stSrcBlend = stDstBlend = -1;
|
||||
stBlendEquation = -1;
|
||||
stAlphaTest = 0;
|
||||
mLastDepthClamp = true;
|
||||
|
||||
mEffectState = 0;
|
||||
activeShader = nullptr;
|
||||
|
||||
mCurrentVertexBuffer = nullptr;
|
||||
mCurrentVertexOffsets[0] = mVertexOffsets[0] = 0;
|
||||
mCurrentIndexBuffer = nullptr;
|
||||
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Apply shader settings
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FGLRenderState::ApplyShader()
|
||||
{
|
||||
static const float nulvec[] = { 0.f, 0.f, 0.f, 0.f };
|
||||
if (mSpecialEffect > EFF_NONE)
|
||||
{
|
||||
activeShader = GLRenderer->mShaderManager->BindEffect(mSpecialEffect, mPassType);
|
||||
}
|
||||
else
|
||||
{
|
||||
activeShader = GLRenderer->mShaderManager->Get(mTextureEnabled ? mEffectState : SHADER_NoTexture, mAlphaThreshold >= 0.f, mPassType);
|
||||
activeShader->Bind();
|
||||
}
|
||||
|
||||
int fogset = 0;
|
||||
|
||||
if (mFogEnabled)
|
||||
{
|
||||
if (mFogEnabled == 2)
|
||||
{
|
||||
fogset = -3; // 2D rendering with 'foggy' overlay.
|
||||
}
|
||||
else if ((GetFogColor() & 0xffffff) == 0)
|
||||
{
|
||||
fogset = gl_fogmode;
|
||||
}
|
||||
else
|
||||
{
|
||||
fogset = -gl_fogmode;
|
||||
}
|
||||
}
|
||||
|
||||
glVertexAttrib4fv(VATTR_COLOR, &mStreamData.uVertexColor.X);
|
||||
glVertexAttrib4fv(VATTR_NORMAL, &mStreamData.uVertexNormal.X);
|
||||
|
||||
activeShader->muDesaturation.Set(mStreamData.uDesaturationFactor);
|
||||
activeShader->muFogEnabled.Set(fogset);
|
||||
|
||||
int f = mTextureModeFlags;
|
||||
if (!mBrightmapEnabled) f &= ~(TEXF_Brightmap | TEXF_Glowmap);
|
||||
activeShader->muTextureMode.Set((mTextureMode == TM_NORMAL && mTempTM == TM_OPAQUE ? TM_OPAQUE : mTextureMode) | f);
|
||||
activeShader->muLightParms.Set(mLightParms);
|
||||
activeShader->muFogColor.Set(mStreamData.uFogColor);
|
||||
activeShader->muObjectColor.Set(mStreamData.uObjectColor);
|
||||
activeShader->muDynLightColor.Set(&mStreamData.uDynLightColor.X);
|
||||
activeShader->muInterpolationFactor.Set(mStreamData.uInterpolationFactor);
|
||||
activeShader->muTimer.Set((double)(screen->FrameTime - firstFrame) * (double)mShaderTimer / 1000.);
|
||||
activeShader->muAlphaThreshold.Set(mAlphaThreshold);
|
||||
activeShader->muLightIndex.Set(-1);
|
||||
activeShader->muClipSplit.Set(mClipSplit);
|
||||
activeShader->muSpecularMaterial.Set(mGlossiness, mSpecularLevel);
|
||||
activeShader->muAddColor.Set(mStreamData.uAddColor);
|
||||
activeShader->muTextureAddColor.Set(mStreamData.uTextureAddColor);
|
||||
activeShader->muTextureModulateColor.Set(mStreamData.uTextureModulateColor);
|
||||
activeShader->muTextureBlendColor.Set(mStreamData.uTextureBlendColor);
|
||||
activeShader->muDetailParms.Set(&mStreamData.uDetailParms.X);
|
||||
|
||||
if (mGlowEnabled || activeShader->currentglowstate)
|
||||
{
|
||||
activeShader->muGlowTopColor.Set(&mStreamData.uGlowTopColor.X);
|
||||
activeShader->muGlowBottomColor.Set(&mStreamData.uGlowBottomColor.X);
|
||||
activeShader->muGlowTopPlane.Set(&mStreamData.uGlowTopPlane.X);
|
||||
activeShader->muGlowBottomPlane.Set(&mStreamData.uGlowBottomPlane.X);
|
||||
activeShader->currentglowstate = mGlowEnabled;
|
||||
}
|
||||
|
||||
if (mGradientEnabled || activeShader->currentgradientstate)
|
||||
{
|
||||
activeShader->muObjectColor2.Set(mStreamData.uObjectColor2);
|
||||
activeShader->muGradientTopPlane.Set(&mStreamData.uGradientTopPlane.X);
|
||||
activeShader->muGradientBottomPlane.Set(&mStreamData.uGradientBottomPlane.X);
|
||||
activeShader->currentgradientstate = mGradientEnabled;
|
||||
}
|
||||
|
||||
if (mSplitEnabled || activeShader->currentsplitstate)
|
||||
{
|
||||
activeShader->muSplitTopPlane.Set(&mStreamData.uSplitTopPlane.X);
|
||||
activeShader->muSplitBottomPlane.Set(&mStreamData.uSplitBottomPlane.X);
|
||||
activeShader->currentsplitstate = mSplitEnabled;
|
||||
}
|
||||
|
||||
|
||||
if (mTextureMatrixEnabled)
|
||||
{
|
||||
matrixToGL(mTextureMatrix, activeShader->texturematrix_index);
|
||||
activeShader->currentTextureMatrixState = true;
|
||||
}
|
||||
else if (activeShader->currentTextureMatrixState)
|
||||
{
|
||||
activeShader->currentTextureMatrixState = false;
|
||||
matrixToGL(identityMatrix, activeShader->texturematrix_index);
|
||||
}
|
||||
|
||||
if (mModelMatrixEnabled)
|
||||
{
|
||||
matrixToGL(mModelMatrix, activeShader->modelmatrix_index);
|
||||
VSMatrix norm;
|
||||
norm.computeNormalMatrix(mModelMatrix);
|
||||
matrixToGL(norm, activeShader->normalmodelmatrix_index);
|
||||
activeShader->currentModelMatrixState = true;
|
||||
}
|
||||
else if (activeShader->currentModelMatrixState)
|
||||
{
|
||||
activeShader->currentModelMatrixState = false;
|
||||
matrixToGL(identityMatrix, activeShader->modelmatrix_index);
|
||||
matrixToGL(identityMatrix, activeShader->normalmodelmatrix_index);
|
||||
}
|
||||
|
||||
int index = mLightIndex;
|
||||
// Mess alert for crappy AncientGL!
|
||||
if (!screen->mLights->GetBufferType() && index >= 0)
|
||||
{
|
||||
size_t start, size;
|
||||
index = screen->mLights->GetBinding(index, &start, &size);
|
||||
|
||||
if (start != mLastMappedLightIndex)
|
||||
{
|
||||
mLastMappedLightIndex = start;
|
||||
static_cast<GLDataBuffer*>(screen->mLights->GetBuffer())->BindRange(nullptr, start, size);
|
||||
}
|
||||
}
|
||||
|
||||
activeShader->muLightIndex.Set(index);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Apply State
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderState::ApplyState()
|
||||
{
|
||||
if (mRenderStyle != stRenderStyle)
|
||||
{
|
||||
ApplyBlendMode();
|
||||
stRenderStyle = mRenderStyle;
|
||||
}
|
||||
|
||||
if (mSplitEnabled != stSplitEnabled)
|
||||
{
|
||||
if (mSplitEnabled)
|
||||
{
|
||||
glEnable(GL_CLIP_DISTANCE3);
|
||||
glEnable(GL_CLIP_DISTANCE4);
|
||||
}
|
||||
else
|
||||
{
|
||||
glDisable(GL_CLIP_DISTANCE3);
|
||||
glDisable(GL_CLIP_DISTANCE4);
|
||||
}
|
||||
stSplitEnabled = mSplitEnabled;
|
||||
}
|
||||
|
||||
if (mMaterial.mChanged)
|
||||
{
|
||||
ApplyMaterial(mMaterial.mMaterial, mMaterial.mClampMode, mMaterial.mTranslation, mMaterial.mOverrideShader);
|
||||
mMaterial.mChanged = false;
|
||||
}
|
||||
|
||||
if (mBias.mChanged)
|
||||
{
|
||||
if (mBias.mFactor == 0 && mBias.mUnits == 0)
|
||||
{
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
}
|
||||
else
|
||||
{
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
}
|
||||
glPolygonOffset(mBias.mFactor, mBias.mUnits);
|
||||
mBias.mChanged = false;
|
||||
}
|
||||
}
|
||||
|
||||
void FGLRenderState::ApplyBuffers()
|
||||
{
|
||||
if (mVertexBuffer != mCurrentVertexBuffer || mVertexOffsets[0] != mCurrentVertexOffsets[0] || mVertexOffsets[1] != mCurrentVertexOffsets[1])
|
||||
{
|
||||
assert(mVertexBuffer != nullptr);
|
||||
static_cast<GLVertexBuffer*>(mVertexBuffer)->Bind(mVertexOffsets);
|
||||
mCurrentVertexBuffer = mVertexBuffer;
|
||||
mCurrentVertexOffsets[0] = mVertexOffsets[0];
|
||||
mCurrentVertexOffsets[1] = mVertexOffsets[1];
|
||||
}
|
||||
if (mIndexBuffer != mCurrentIndexBuffer)
|
||||
{
|
||||
if (mIndexBuffer) static_cast<GLIndexBuffer*>(mIndexBuffer)->Bind();
|
||||
mCurrentIndexBuffer = mIndexBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
void FGLRenderState::Apply()
|
||||
{
|
||||
ApplyState();
|
||||
ApplyBuffers();
|
||||
ApplyShader();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Binds a texture to the renderer
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FGLRenderState::ApplyMaterial(FMaterial *mat, int clampmode, int translation, int overrideshader)
|
||||
{
|
||||
if (mat->Source()->isHardwareCanvas())
|
||||
{
|
||||
mTempTM = TM_OPAQUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
mTempTM = TM_NORMAL;
|
||||
}
|
||||
auto tex = mat->Source();
|
||||
mEffectState = overrideshader >= 0 ? overrideshader : mat->GetShaderIndex();
|
||||
mShaderTimer = tex->GetShaderSpeed();
|
||||
SetSpecular(tex->GetGlossiness(), tex->GetSpecularLevel());
|
||||
if (tex->isHardwareCanvas()) static_cast<FCanvasTexture*>(tex->GetTexture())->NeedUpdate();
|
||||
|
||||
clampmode = tex->GetClampMode(clampmode);
|
||||
|
||||
// avoid rebinding the same texture multiple times.
|
||||
if (mat == lastMaterial && lastClamp == clampmode && translation == lastTranslation) return;
|
||||
lastMaterial = mat;
|
||||
lastClamp = clampmode;
|
||||
lastTranslation = translation;
|
||||
|
||||
int usebright = false;
|
||||
int maxbound = 0;
|
||||
|
||||
int numLayers = mat->NumLayers();
|
||||
MaterialLayerInfo* layer;
|
||||
auto base = static_cast<FHardwareTexture*>(mat->GetLayer(0, translation, &layer));
|
||||
|
||||
if (base->BindOrCreate(tex->GetTexture(), 0, clampmode, translation, layer->scaleFlags))
|
||||
{
|
||||
for (int i = 1; i<numLayers; i++)
|
||||
{
|
||||
auto systex = static_cast<FHardwareTexture*>(mat->GetLayer(i, 0, &layer));
|
||||
// fixme: Upscale flags must be disabled for certain layers.
|
||||
systex->BindOrCreate(layer->layerTexture, i, clampmode, 0, layer->scaleFlags);
|
||||
maxbound = i;
|
||||
}
|
||||
}
|
||||
// unbind everything from the last texture that's still active
|
||||
for (int i = maxbound + 1; i <= maxBoundMaterial; i++)
|
||||
{
|
||||
FHardwareTexture::Unbind(i);
|
||||
maxBoundMaterial = maxbound;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Apply blend mode from RenderStyle
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderState::ApplyBlendMode()
|
||||
{
|
||||
static int blendstyles[] = { GL_ZERO, GL_ONE, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR, GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA };
|
||||
static int renderops[] = { 0, GL_FUNC_ADD, GL_FUNC_SUBTRACT, GL_FUNC_REVERSE_SUBTRACT, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1 };
|
||||
|
||||
int srcblend = blendstyles[mRenderStyle.SrcAlpha%STYLEALPHA_MAX];
|
||||
int dstblend = blendstyles[mRenderStyle.DestAlpha%STYLEALPHA_MAX];
|
||||
int blendequation = renderops[mRenderStyle.BlendOp & 15];
|
||||
|
||||
if (blendequation == -1) // This was a fuzz style.
|
||||
{
|
||||
srcblend = GL_DST_COLOR;
|
||||
dstblend = GL_ONE_MINUS_SRC_ALPHA;
|
||||
blendequation = GL_FUNC_ADD;
|
||||
}
|
||||
|
||||
// Checks must be disabled until all draw code has been converted.
|
||||
//if (srcblend != stSrcBlend || dstblend != stDstBlend)
|
||||
{
|
||||
stSrcBlend = srcblend;
|
||||
stDstBlend = dstblend;
|
||||
glBlendFunc(srcblend, dstblend);
|
||||
}
|
||||
//if (blendequation != stBlendEquation)
|
||||
{
|
||||
stBlendEquation = blendequation;
|
||||
glBlendEquation(blendequation);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// API dependent draw calls
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static int dt2gl[] = { GL_POINTS, GL_LINES, GL_TRIANGLES, GL_TRIANGLE_FAN, GL_TRIANGLE_STRIP };
|
||||
|
||||
void FGLRenderState::Draw(int dt, int index, int count, bool apply)
|
||||
{
|
||||
if (apply)
|
||||
{
|
||||
Apply();
|
||||
}
|
||||
drawcalls.Clock();
|
||||
glDrawArrays(dt2gl[dt], index, count);
|
||||
drawcalls.Unclock();
|
||||
}
|
||||
|
||||
void FGLRenderState::DrawIndexed(int dt, int index, int count, bool apply)
|
||||
{
|
||||
if (apply)
|
||||
{
|
||||
Apply();
|
||||
}
|
||||
drawcalls.Clock();
|
||||
glDrawElements(dt2gl[dt], count, GL_UNSIGNED_INT, (void*)(intptr_t)(index * sizeof(uint32_t)));
|
||||
drawcalls.Unclock();
|
||||
}
|
||||
|
||||
void FGLRenderState::SetDepthMask(bool on)
|
||||
{
|
||||
glDepthMask(on);
|
||||
}
|
||||
|
||||
void FGLRenderState::SetDepthFunc(int func)
|
||||
{
|
||||
static int df2gl[] = { GL_LESS, GL_LEQUAL, GL_ALWAYS };
|
||||
glDepthFunc(df2gl[func]);
|
||||
}
|
||||
|
||||
void FGLRenderState::SetDepthRange(float min, float max)
|
||||
{
|
||||
glDepthRange(min, max);
|
||||
}
|
||||
|
||||
void FGLRenderState::SetColorMask(bool r, bool g, bool b, bool a)
|
||||
{
|
||||
glColorMask(r, g, b, a);
|
||||
}
|
||||
|
||||
void FGLRenderState::SetStencil(int offs, int op, int flags = -1)
|
||||
{
|
||||
static int op2gl[] = { GL_KEEP, GL_INCR, GL_DECR };
|
||||
|
||||
glStencilFunc(GL_EQUAL, screen->stencilValue + offs, ~0); // draw sky into stencil
|
||||
glStencilOp(GL_KEEP, GL_KEEP, op2gl[op]); // this stage doesn't modify the stencil
|
||||
|
||||
if (flags != -1)
|
||||
{
|
||||
bool cmon = !(flags & SF_ColorMaskOff);
|
||||
glColorMask(cmon, cmon, cmon, cmon); // don't write to the graphics buffer
|
||||
glDepthMask(!(flags & SF_DepthMaskOff));
|
||||
}
|
||||
}
|
||||
|
||||
void FGLRenderState::ToggleState(int state, bool on)
|
||||
{
|
||||
if (on)
|
||||
{
|
||||
glEnable(state);
|
||||
}
|
||||
else
|
||||
{
|
||||
glDisable(state);
|
||||
}
|
||||
}
|
||||
|
||||
void FGLRenderState::SetCulling(int mode)
|
||||
{
|
||||
if (mode != Cull_None)
|
||||
{
|
||||
glEnable(GL_CULL_FACE);
|
||||
glFrontFace(mode == Cull_CCW ? GL_CCW : GL_CW);
|
||||
}
|
||||
else
|
||||
{
|
||||
glDisable(GL_CULL_FACE);
|
||||
}
|
||||
}
|
||||
|
||||
void FGLRenderState::EnableClipDistance(int num, bool state)
|
||||
{
|
||||
// Update the viewpoint-related clip plane setting.
|
||||
if (!(gl.flags & RFL_NO_CLIP_PLANES))
|
||||
{
|
||||
ToggleState(GL_CLIP_DISTANCE0 + num, state);
|
||||
}
|
||||
}
|
||||
|
||||
void FGLRenderState::Clear(int targets)
|
||||
{
|
||||
// This always clears to default values.
|
||||
int gltarget = 0;
|
||||
if (targets & CT_Depth)
|
||||
{
|
||||
gltarget |= GL_DEPTH_BUFFER_BIT;
|
||||
glClearDepth(1);
|
||||
}
|
||||
if (targets & CT_Stencil)
|
||||
{
|
||||
gltarget |= GL_STENCIL_BUFFER_BIT;
|
||||
glClearStencil(0);
|
||||
}
|
||||
if (targets & CT_Color)
|
||||
{
|
||||
gltarget |= GL_COLOR_BUFFER_BIT;
|
||||
glClearColor(screen->mSceneClearColor[0], screen->mSceneClearColor[1], screen->mSceneClearColor[2], screen->mSceneClearColor[3]);
|
||||
}
|
||||
glClear(gltarget);
|
||||
}
|
||||
|
||||
void FGLRenderState::EnableStencil(bool on)
|
||||
{
|
||||
ToggleState(GL_STENCIL_TEST, on);
|
||||
}
|
||||
|
||||
void FGLRenderState::SetScissor(int x, int y, int w, int h)
|
||||
{
|
||||
if (w > -1)
|
||||
{
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glScissor(x, y, w, h);
|
||||
}
|
||||
else
|
||||
{
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
}
|
||||
|
||||
void FGLRenderState::SetViewport(int x, int y, int w, int h)
|
||||
{
|
||||
glViewport(x, y, w, h);
|
||||
}
|
||||
|
||||
void FGLRenderState::EnableDepthTest(bool on)
|
||||
{
|
||||
ToggleState(GL_DEPTH_TEST, on);
|
||||
}
|
||||
|
||||
void FGLRenderState::EnableMultisampling(bool on)
|
||||
{
|
||||
ToggleState(GL_MULTISAMPLE, on);
|
||||
}
|
||||
|
||||
void FGLRenderState::EnableLineSmooth(bool on)
|
||||
{
|
||||
ToggleState(GL_LINE_SMOOTH, on);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void FGLRenderState::ClearScreen()
|
||||
{
|
||||
bool multi = !!glIsEnabled(GL_MULTISAMPLE);
|
||||
|
||||
screen->mViewpoints->Set2D(*this, SCREENWIDTH, SCREENHEIGHT);
|
||||
SetColor(0, 0, 0);
|
||||
Apply();
|
||||
|
||||
glDisable(GL_MULTISAMPLE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, FFlatVertexBuffer::FULLSCREEN_INDEX, 4);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
if (multi) glEnable(GL_MULTISAMPLE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Below are less frequently altrered state settings which do not get
|
||||
// buffered by the state object, but set directly instead.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FGLRenderState::SetDepthClamp(bool on)
|
||||
{
|
||||
bool res = mLastDepthClamp;
|
||||
if (!on) glDisable(GL_DEPTH_CLAMP);
|
||||
else glEnable(GL_DEPTH_CLAMP);
|
||||
mLastDepthClamp = on;
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,152 +0,0 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2009-2016 Christoph Oelckers
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
#ifndef __GL_RENDERSTATE_H
|
||||
#define __GL_RENDERSTATE_H
|
||||
|
||||
#include <string.h>
|
||||
#include "gl_interface.h"
|
||||
#include "matrix.h"
|
||||
#include "hwrenderer/scene//hw_drawstructs.h"
|
||||
#include "hw_renderstate.h"
|
||||
#include "hw_material.h"
|
||||
#include "c_cvars.h"
|
||||
#include "r_defs.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
namespace OpenGLRenderer
|
||||
{
|
||||
|
||||
class FShader;
|
||||
struct HWSectorPlane;
|
||||
|
||||
class FGLRenderState final : public FRenderState
|
||||
{
|
||||
uint8_t mLastDepthClamp : 1;
|
||||
|
||||
float mGlossiness, mSpecularLevel;
|
||||
float mShaderTimer;
|
||||
|
||||
int mEffectState;
|
||||
int mTempTM = TM_NORMAL;
|
||||
|
||||
FRenderStyle stRenderStyle;
|
||||
int stSrcBlend, stDstBlend;
|
||||
bool stAlphaTest;
|
||||
bool stSplitEnabled;
|
||||
int stBlendEquation;
|
||||
|
||||
FShader *activeShader;
|
||||
|
||||
int mNumDrawBuffers = 1;
|
||||
|
||||
bool ApplyShader();
|
||||
void ApplyState();
|
||||
|
||||
// Texture binding state
|
||||
FMaterial *lastMaterial = nullptr;
|
||||
int lastClamp = 0;
|
||||
int lastTranslation = 0;
|
||||
int maxBoundMaterial = -1;
|
||||
size_t mLastMappedLightIndex = SIZE_MAX;
|
||||
|
||||
IVertexBuffer *mCurrentVertexBuffer;
|
||||
int mCurrentVertexOffsets[2]; // one per binding point
|
||||
IIndexBuffer *mCurrentIndexBuffer;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
FGLRenderState()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset();
|
||||
|
||||
void ClearLastMaterial()
|
||||
{
|
||||
lastMaterial = nullptr;
|
||||
}
|
||||
|
||||
void ApplyMaterial(FMaterial *mat, int clampmode, int translation, int overrideshader);
|
||||
|
||||
void Apply();
|
||||
void ApplyBuffers();
|
||||
void ApplyBlendMode();
|
||||
|
||||
void ResetVertexBuffer()
|
||||
{
|
||||
// forces rebinding with the next 'apply' call.
|
||||
mCurrentVertexBuffer = nullptr;
|
||||
mCurrentIndexBuffer = nullptr;
|
||||
}
|
||||
|
||||
void SetSpecular(float glossiness, float specularLevel)
|
||||
{
|
||||
mGlossiness = glossiness;
|
||||
mSpecularLevel = specularLevel;
|
||||
}
|
||||
|
||||
void EnableDrawBuffers(int count, bool apply = false) override
|
||||
{
|
||||
count = MIN(count, 3);
|
||||
if (mNumDrawBuffers != count)
|
||||
{
|
||||
static GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 };
|
||||
glDrawBuffers(count, buffers);
|
||||
mNumDrawBuffers = count;
|
||||
}
|
||||
if (apply) Apply();
|
||||
}
|
||||
|
||||
void ToggleState(int state, bool on);
|
||||
|
||||
void ClearScreen() override;
|
||||
void Draw(int dt, int index, int count, bool apply = true) override;
|
||||
void DrawIndexed(int dt, int index, int count, bool apply = true) override;
|
||||
|
||||
bool SetDepthClamp(bool on) override;
|
||||
void SetDepthMask(bool on) override;
|
||||
void SetDepthFunc(int func) override;
|
||||
void SetDepthRange(float min, float max) override;
|
||||
void SetColorMask(bool r, bool g, bool b, bool a) override;
|
||||
void SetStencil(int offs, int op, int flags) override;
|
||||
void SetCulling(int mode) override;
|
||||
void EnableClipDistance(int num, bool state) override;
|
||||
void Clear(int targets) override;
|
||||
void EnableStencil(bool on) override;
|
||||
void SetScissor(int x, int y, int w, int h) override;
|
||||
void SetViewport(int x, int y, int w, int h) override;
|
||||
void EnableDepthTest(bool on) override;
|
||||
void EnableMultisampling(bool on) override;
|
||||
void EnableLineSmooth(bool on) override;
|
||||
|
||||
|
||||
};
|
||||
|
||||
extern FGLRenderState gl_RenderState;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -27,13 +27,13 @@
|
|||
|
||||
#include "gl_system.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/renderer/gl_renderbuffers.h"
|
||||
#include "gl_renderbuffers.h"
|
||||
#include "hw_vrmodes.h"
|
||||
#include "gl/system/gl_framebuffer.h"
|
||||
#include "gl/renderer/gl_postprocessstate.h"
|
||||
#include "gl_postprocessstate.h"
|
||||
#include "gl/system/gl_framebuffer.h"
|
||||
#include "gl/shaders/gl_shaderprogram.h"
|
||||
#include "gl/system/gl_buffers.h"
|
||||
#include "gl_buffers.h"
|
||||
#include "menu/menu.h"
|
||||
|
||||
EXTERN_CVAR(Int, vr_mode)
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@
|
|||
#include "hw_lightbuffer.h"
|
||||
|
||||
#include "gl_interface.h"
|
||||
#include "gl/system/gl_debug.h"
|
||||
#include "gl_debug.h"
|
||||
#include "matrix.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/shaders/gl_shader.h"
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
#ifndef __GL_SHADERS_H__
|
||||
#define __GL_SHADERS_H__
|
||||
|
||||
#include "gl/renderer/gl_renderstate.h"
|
||||
#include "gl_renderstate.h"
|
||||
#include "name.h"
|
||||
|
||||
extern bool gl_shaderactive;
|
||||
|
|
|
|||
|
|
@ -1,35 +1,29 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2016 Magnus Norddahl
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
/*
|
||||
** gl_shaderprogram.cpp
|
||||
** GLSL shader program compile and link
|
||||
** Postprocessing framework
|
||||
** Copyright (c) 2016-2020 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "gl_system.h"
|
||||
#include "v_video.h"
|
||||
#include "gl_interface.h"
|
||||
#include "hw_cvars.h"
|
||||
#include "gl/system/gl_debug.h"
|
||||
#include "gl_debug.h"
|
||||
#include "gl/shaders/gl_shaderprogram.h"
|
||||
#include "hwrenderer/utility/hw_shaderpatcher.h"
|
||||
#include "filesystem.h"
|
||||
|
|
@ -268,7 +262,7 @@ FString FShaderProgram::PatchShader(ShaderType type, const FString &code, const
|
|||
|
||||
// If we have 4.2, always use it because it adds important new syntax.
|
||||
if (maxGlslVersion < 420 && gl.glslversion >= 4.2f) maxGlslVersion = 420;
|
||||
int shaderVersion = MIN((int)round(gl.glslversion * 10) * 10, maxGlslVersion);
|
||||
int shaderVersion = std::min((int)round(gl.glslversion * 10) * 10, maxGlslVersion);
|
||||
patchedCode.AppendFormat("#version %d\n", shaderVersion);
|
||||
|
||||
// TODO: Find some way to add extension requirements to the patching
|
||||
|
|
|
|||
|
|
@ -1,223 +0,0 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2018 Christoph Oelckers
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
/*
|
||||
** Low level vertex buffer class
|
||||
**
|
||||
**/
|
||||
|
||||
#include "gl_system.h"
|
||||
#include "gl_buffers.h"
|
||||
#include "gl/renderer/gl_renderstate.h"
|
||||
#include "v_video.h"
|
||||
|
||||
namespace OpenGLRenderer
|
||||
{
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// basic buffer implementation
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static inline void InvalidateBufferState()
|
||||
{
|
||||
gl_RenderState.ResetVertexBuffer(); // force rebinding of buffers on next Apply call.
|
||||
}
|
||||
|
||||
GLBuffer::GLBuffer(int usetype)
|
||||
: mUseType(usetype)
|
||||
{
|
||||
glGenBuffers(1, &mBufferId);
|
||||
}
|
||||
|
||||
GLBuffer::~GLBuffer()
|
||||
{
|
||||
if (mBufferId != 0)
|
||||
{
|
||||
glBindBuffer(mUseType, mBufferId);
|
||||
glUnmapBuffer(mUseType);
|
||||
glBindBuffer(mUseType, 0);
|
||||
glDeleteBuffers(1, &mBufferId);
|
||||
}
|
||||
}
|
||||
|
||||
void GLBuffer::Bind()
|
||||
{
|
||||
glBindBuffer(mUseType, mBufferId);
|
||||
}
|
||||
|
||||
|
||||
void GLBuffer::SetData(size_t size, const void *data, bool staticdata)
|
||||
{
|
||||
Bind();
|
||||
if (data != nullptr)
|
||||
{
|
||||
glBufferData(mUseType, size, data, staticdata? GL_STATIC_DRAW : GL_STREAM_DRAW);
|
||||
}
|
||||
else
|
||||
{
|
||||
mPersistent = screen->BuffersArePersistent() && !staticdata;
|
||||
if (mPersistent)
|
||||
{
|
||||
glBufferStorage(mUseType, size, nullptr, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
|
||||
map = glMapBufferRange(mUseType, 0, size, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
|
||||
}
|
||||
else
|
||||
{
|
||||
glBufferData(mUseType, size, nullptr, staticdata ? GL_STATIC_DRAW : GL_STREAM_DRAW);
|
||||
map = nullptr;
|
||||
}
|
||||
if (!staticdata) nomap = false;
|
||||
}
|
||||
buffersize = size;
|
||||
InvalidateBufferState();
|
||||
}
|
||||
|
||||
void GLBuffer::SetSubData(size_t offset, size_t size, const void *data)
|
||||
{
|
||||
Bind();
|
||||
glBufferSubData(mUseType, offset, size, data);
|
||||
}
|
||||
|
||||
void GLBuffer::Map()
|
||||
{
|
||||
assert(nomap == false); // do not allow mapping of static buffers. Vulkan cannot do that so it should be blocked in OpenGL, too.
|
||||
if (!mPersistent && !nomap)
|
||||
{
|
||||
Bind();
|
||||
map = (FFlatVertex*)glMapBufferRange(mUseType, 0, buffersize, GL_MAP_WRITE_BIT|GL_MAP_UNSYNCHRONIZED_BIT);
|
||||
InvalidateBufferState();
|
||||
}
|
||||
}
|
||||
|
||||
void GLBuffer::Unmap()
|
||||
{
|
||||
assert(nomap == false);
|
||||
if (!mPersistent && map != nullptr)
|
||||
{
|
||||
Bind();
|
||||
glUnmapBuffer(mUseType);
|
||||
InvalidateBufferState();
|
||||
map = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void *GLBuffer::Lock(unsigned int size)
|
||||
{
|
||||
// This initializes this buffer as a static object with no data.
|
||||
SetData(size, nullptr, true);
|
||||
return glMapBufferRange(mUseType, 0, size, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
|
||||
}
|
||||
|
||||
void GLBuffer::Unlock()
|
||||
{
|
||||
Bind();
|
||||
glUnmapBuffer(mUseType);
|
||||
InvalidateBufferState();
|
||||
}
|
||||
|
||||
void GLBuffer::Resize(size_t newsize)
|
||||
{
|
||||
assert(!nomap); // only mappable buffers can be resized.
|
||||
if (newsize > buffersize && !nomap)
|
||||
{
|
||||
// reallocate the buffer with twice the size
|
||||
unsigned int oldbuffer = mBufferId;
|
||||
|
||||
// first unmap the old buffer
|
||||
Bind();
|
||||
glUnmapBuffer(mUseType);
|
||||
|
||||
glGenBuffers(1, &mBufferId);
|
||||
SetData(newsize, nullptr, false);
|
||||
glBindBuffer(GL_COPY_READ_BUFFER, oldbuffer);
|
||||
|
||||
// copy contents and delete the old buffer.
|
||||
glCopyBufferSubData(GL_COPY_READ_BUFFER, mUseType, 0, 0, buffersize);
|
||||
glBindBuffer(GL_COPY_READ_BUFFER, 0);
|
||||
glDeleteBuffers(1, &oldbuffer);
|
||||
buffersize = newsize;
|
||||
InvalidateBufferState();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Vertex buffer implementation
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void GLVertexBuffer::SetFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs)
|
||||
{
|
||||
static int VFmtToGLFmt[] = { GL_FLOAT, GL_FLOAT, GL_FLOAT, GL_FLOAT, GL_UNSIGNED_BYTE, GL_INT_2_10_10_10_REV };
|
||||
static uint8_t VFmtToSize[] = {4, 3, 2, 1, 4, 4};
|
||||
|
||||
mStride = stride;
|
||||
mNumBindingPoints = numBindingPoints;
|
||||
|
||||
for(int i = 0; i < numAttributes; i++)
|
||||
{
|
||||
if (attrs[i].location >= 0 && attrs[i].location < VATTR_MAX)
|
||||
{
|
||||
auto & attrinf = mAttributeInfo[attrs[i].location];
|
||||
attrinf.format = VFmtToGLFmt[attrs[i].format];
|
||||
attrinf.size = VFmtToSize[attrs[i].format];
|
||||
attrinf.offset = attrs[i].offset;
|
||||
attrinf.bindingpoint = attrs[i].binding;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GLVertexBuffer::Bind(int *offsets)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
// This is what gets called from RenderState.Apply. It shouldn't be called anywhere else if the render state is in use
|
||||
GLBuffer::Bind();
|
||||
for(auto &attrinf : mAttributeInfo)
|
||||
{
|
||||
if (attrinf.size == 0)
|
||||
{
|
||||
glDisableVertexAttribArray(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
glEnableVertexAttribArray(i);
|
||||
size_t ofs = offsets == nullptr ? attrinf.offset : attrinf.offset + mStride * offsets[attrinf.bindingpoint];
|
||||
glVertexAttribPointer(i, attrinf.size, attrinf.format, attrinf.format != GL_FLOAT, (GLsizei)mStride, (void*)(intptr_t)ofs);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void GLDataBuffer::BindRange(FRenderState *state, size_t start, size_t length)
|
||||
{
|
||||
glBindBufferRange(mUseType, mBindingPoint, mBufferId, start, length);
|
||||
}
|
||||
|
||||
void GLDataBuffer::BindBase()
|
||||
{
|
||||
glBindBufferBase(mUseType, mBindingPoint, mBufferId);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "hwrenderer/data/buffers.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// silence bogus warning C4250: 'GLVertexBuffer': inherits 'GLBuffer::GLBuffer::SetData' via dominance
|
||||
// According to internet infos, the warning is erroneously emitted in this case.
|
||||
#pragma warning(disable:4250)
|
||||
#endif
|
||||
|
||||
namespace OpenGLRenderer
|
||||
{
|
||||
|
||||
class GLBuffer : virtual public IBuffer
|
||||
{
|
||||
protected:
|
||||
const int mUseType;
|
||||
unsigned int mBufferId;
|
||||
int mAllocationSize = 0;
|
||||
bool mPersistent = false;
|
||||
bool nomap = true;
|
||||
|
||||
GLBuffer(int usetype);
|
||||
~GLBuffer();
|
||||
void SetData(size_t size, const void *data, bool staticdata) override;
|
||||
void SetSubData(size_t offset, size_t size, const void *data) override;
|
||||
void Map() override;
|
||||
void Unmap() override;
|
||||
void Resize(size_t newsize) override;
|
||||
void *Lock(unsigned int size) override;
|
||||
void Unlock() override;
|
||||
public:
|
||||
void Bind();
|
||||
};
|
||||
|
||||
|
||||
class GLVertexBuffer : public IVertexBuffer, public GLBuffer
|
||||
{
|
||||
// If this could use the modern (since GL 4.3) binding system, things would be simpler... :(
|
||||
struct GLVertexBufferAttribute
|
||||
{
|
||||
int bindingpoint;
|
||||
int format;
|
||||
int size;
|
||||
int offset;
|
||||
};
|
||||
|
||||
int mNumBindingPoints;
|
||||
GLVertexBufferAttribute mAttributeInfo[VATTR_MAX] = {}; // Thanks to OpenGL's state system this needs to contain info about every attribute that may ever be in use throughout the entire renderer.
|
||||
size_t mStride = 0;
|
||||
|
||||
public:
|
||||
GLVertexBuffer() : GLBuffer(GL_ARRAY_BUFFER) {}
|
||||
void SetFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs) override;
|
||||
void Bind(int *offsets);
|
||||
};
|
||||
|
||||
class GLIndexBuffer : public IIndexBuffer, public GLBuffer
|
||||
{
|
||||
public:
|
||||
GLIndexBuffer() : GLBuffer(GL_ELEMENT_ARRAY_BUFFER) {}
|
||||
};
|
||||
|
||||
class GLDataBuffer : public IDataBuffer, public GLBuffer
|
||||
{
|
||||
int mBindingPoint;
|
||||
public:
|
||||
GLDataBuffer(int bindingpoint, bool is_ssbo) : GLBuffer(is_ssbo? GL_SHADER_STORAGE_BUFFER : GL_UNIFORM_BUFFER), mBindingPoint(bindingpoint) {}
|
||||
void BindRange(FRenderState* state, size_t start, size_t length);
|
||||
void BindBase();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -1,370 +0,0 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2016 Magnus Norddahl
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
/*
|
||||
** gl_debig.cpp
|
||||
** OpenGL debugging support functions
|
||||
**
|
||||
*/
|
||||
|
||||
#include "templates.h"
|
||||
#include "gl_system.h"
|
||||
#include "gl/system/gl_debug.h"
|
||||
#include "stats.h"
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
CUSTOM_CVAR(Int, gl_debug_level, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
|
||||
{
|
||||
if (!OpenGLRenderer::FGLDebug::HasDebugApi())
|
||||
{
|
||||
Printf("No OpenGL debug support detected.\n");
|
||||
}
|
||||
}
|
||||
|
||||
CVAR(Bool, gl_debug_breakpoint, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
|
||||
|
||||
extern bool gpuStatActive;
|
||||
extern bool keepGpuStatActive;
|
||||
extern FString gpuStatOutput;
|
||||
|
||||
namespace OpenGLRenderer
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
std::vector<std::pair<FString, GLuint>> timeElapsedQueries;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Updates OpenGL debugging state
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FGLDebug::Update()
|
||||
{
|
||||
gpuStatOutput = "";
|
||||
for (auto &query : timeElapsedQueries)
|
||||
{
|
||||
GLuint timeElapsed = 0;
|
||||
glGetQueryObjectuiv(query.second, GL_QUERY_RESULT, &timeElapsed);
|
||||
glDeleteQueries(1, &query.second);
|
||||
|
||||
FString out;
|
||||
out.Format("%s=%04.2f ms\n", query.first.GetChars(), timeElapsed / 1000000.0f);
|
||||
gpuStatOutput += out;
|
||||
}
|
||||
timeElapsedQueries.clear();
|
||||
|
||||
gpuStatActive = keepGpuStatActive;
|
||||
keepGpuStatActive = false;
|
||||
|
||||
if (!HasDebugApi())
|
||||
return;
|
||||
|
||||
SetupBreakpointMode();
|
||||
UpdateLoggingLevel();
|
||||
OutputMessageLog();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Label objects so they are referenced by name in debug messages and in
|
||||
// OpenGL debuggers (renderdoc)
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FGLDebug::LabelObject(GLenum type, GLuint handle, const char *name)
|
||||
{
|
||||
if (HasDebugApi() && gl_debug_level != 0)
|
||||
{
|
||||
glObjectLabel(type, handle, -1, name);
|
||||
}
|
||||
}
|
||||
|
||||
void FGLDebug::LabelObjectPtr(void *ptr, const char *name)
|
||||
{
|
||||
if (HasDebugApi() && gl_debug_level != 0)
|
||||
{
|
||||
glObjectPtrLabel(ptr, -1, name);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Marks which render pass/group is executing commands so that debuggers can
|
||||
// display this information
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FGLDebug::PushGroup(const FString &name)
|
||||
{
|
||||
if (HasDebugApi() && gl_debug_level != 0)
|
||||
{
|
||||
glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, (GLsizei)name.Len(), name.GetChars());
|
||||
}
|
||||
|
||||
if (gpuStatActive)
|
||||
{
|
||||
GLuint queryHandle = 0;
|
||||
glGenQueries(1, &queryHandle);
|
||||
glBeginQuery(GL_TIME_ELAPSED, queryHandle);
|
||||
timeElapsedQueries.push_back({ name, queryHandle });
|
||||
}
|
||||
}
|
||||
|
||||
void FGLDebug::PopGroup()
|
||||
{
|
||||
if (HasDebugApi() && gl_debug_level != 0)
|
||||
{
|
||||
glPopDebugGroup();
|
||||
}
|
||||
|
||||
if (gpuStatActive)
|
||||
{
|
||||
glEndQuery(GL_TIME_ELAPSED);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Turns on synchronous debugging on and off based on gl_debug_breakpoint
|
||||
//
|
||||
// Allows getting the debugger to break exactly at the OpenGL function emitting
|
||||
// a message.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FGLDebug::SetupBreakpointMode()
|
||||
{
|
||||
if (mBreakpointMode != gl_debug_breakpoint)
|
||||
{
|
||||
if (gl_debug_breakpoint)
|
||||
{
|
||||
glDebugMessageCallback(&FGLDebug::DebugCallback, this);
|
||||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||
}
|
||||
else
|
||||
{
|
||||
glDebugMessageCallback(nullptr, nullptr);
|
||||
glDisable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||
}
|
||||
mBreakpointMode = gl_debug_breakpoint;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Tells OpenGL which debug messages we are interested in
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FGLDebug::UpdateLoggingLevel()
|
||||
{
|
||||
const GLenum level = gl_debug_level;
|
||||
if (level != mCurrentLevel)
|
||||
{
|
||||
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH, 0, nullptr, level > 0);
|
||||
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM, 0, nullptr, level > 1);
|
||||
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW, 0, nullptr, level > 2);
|
||||
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION, 0, nullptr, level > 3);
|
||||
mCurrentLevel = level;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// The log may already contain entries for a debug level we are no longer
|
||||
// interested in..
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool FGLDebug::IsFilteredByDebugLevel(GLenum severity)
|
||||
{
|
||||
int severityLevel = 0;
|
||||
switch (severity)
|
||||
{
|
||||
case GL_DEBUG_SEVERITY_HIGH: severityLevel = 1; break;
|
||||
case GL_DEBUG_SEVERITY_MEDIUM: severityLevel = 2; break;
|
||||
case GL_DEBUG_SEVERITY_LOW: severityLevel = 3; break;
|
||||
case GL_DEBUG_SEVERITY_NOTIFICATION: severityLevel = 4; break;
|
||||
}
|
||||
return severityLevel > (int)gl_debug_level;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Prints all logged messages to the console
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FGLDebug::OutputMessageLog()
|
||||
{
|
||||
if (mCurrentLevel <= 0)
|
||||
return;
|
||||
|
||||
GLint maxDebugMessageLength = 0;
|
||||
glGetIntegerv(GL_MAX_DEBUG_MESSAGE_LENGTH, &maxDebugMessageLength);
|
||||
|
||||
const int maxMessages = 50;
|
||||
const int messageLogSize = maxMessages * maxDebugMessageLength;
|
||||
|
||||
TArray<GLenum> sources, types, severities;
|
||||
TArray<GLuint> ids;
|
||||
TArray<GLsizei> lengths;
|
||||
TArray<GLchar> messageLog;
|
||||
|
||||
sources.Resize(maxMessages);
|
||||
types.Resize(maxMessages);
|
||||
severities.Resize(maxMessages);
|
||||
ids.Resize(maxMessages);
|
||||
lengths.Resize(maxMessages);
|
||||
messageLog.Resize(messageLogSize);
|
||||
|
||||
while (true)
|
||||
{
|
||||
GLuint numMessages = glGetDebugMessageLog(maxMessages, messageLogSize, &sources[0], &types[0], &ids[0], &severities[0], &lengths[0], &messageLog[0]);
|
||||
if (numMessages <= 0) break;
|
||||
|
||||
GLsizei offset = 0;
|
||||
for (GLuint i = 0; i < numMessages; i++)
|
||||
{
|
||||
if (!IsFilteredByDebugLevel(severities[i]))
|
||||
PrintMessage(sources[i], types[i], ids[i], severities[i], lengths[i], &messageLog[offset]);
|
||||
offset += lengths[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Print a single message to the console
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FGLDebug::PrintMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message)
|
||||
{
|
||||
if (type == GL_DEBUG_TYPE_PUSH_GROUP || type == GL_DEBUG_TYPE_POP_GROUP)
|
||||
return;
|
||||
|
||||
const int maxMessages = 50;
|
||||
|
||||
static int messagesPrinted = 0;
|
||||
if (messagesPrinted > maxMessages)
|
||||
return;
|
||||
|
||||
FString msg(message, length);
|
||||
|
||||
static std::set<std::string> seenMessages;
|
||||
bool alreadySeen = !seenMessages.insert(msg.GetChars()).second;
|
||||
if (alreadySeen)
|
||||
return;
|
||||
|
||||
messagesPrinted++;
|
||||
if (messagesPrinted == maxMessages)
|
||||
{
|
||||
Printf("Max OpenGL debug messages reached. Suppressing further output.\n");
|
||||
}
|
||||
else if (messagesPrinted < maxMessages)
|
||||
{
|
||||
FString sourceStr = SourceToString(source);
|
||||
FString typeStr = TypeToString(type);
|
||||
FString severityStr = SeverityToString(severity);
|
||||
if (type != GL_DEBUG_TYPE_OTHER)
|
||||
Printf("[%s] %s, %s: %s\n", sourceStr.GetChars(), severityStr.GetChars(), typeStr.GetChars(), msg.GetChars());
|
||||
else
|
||||
Printf("[%s] %s: %s\n", sourceStr.GetChars(), severityStr.GetChars(), msg.GetChars());
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// OpenGL callback function used when synchronous debugging is enabled
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FGLDebug::DebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam)
|
||||
{
|
||||
if (IsFilteredByDebugLevel(severity))
|
||||
return;
|
||||
|
||||
PrintMessage(source, type, id, severity, length, message);
|
||||
assert(severity == GL_DEBUG_SEVERITY_NOTIFICATION);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Enum to string helpers
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
FString FGLDebug::SourceToString(GLenum source)
|
||||
{
|
||||
FString s;
|
||||
switch (source)
|
||||
{
|
||||
case GL_DEBUG_SOURCE_API: s = "api"; break;
|
||||
case GL_DEBUG_SOURCE_WINDOW_SYSTEM: s = "window system"; break;
|
||||
case GL_DEBUG_SOURCE_SHADER_COMPILER: s = "shader compiler"; break;
|
||||
case GL_DEBUG_SOURCE_THIRD_PARTY: s = "third party"; break;
|
||||
case GL_DEBUG_SOURCE_APPLICATION: s = "application"; break;
|
||||
case GL_DEBUG_SOURCE_OTHER: s = "other"; break;
|
||||
default: s.Format("%d", (int)source);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
FString FGLDebug::TypeToString(GLenum type)
|
||||
{
|
||||
FString s;
|
||||
switch (type)
|
||||
{
|
||||
case GL_DEBUG_TYPE_ERROR: s = "error"; break;
|
||||
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: s = "deprecated"; break;
|
||||
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: s = "undefined"; break;
|
||||
case GL_DEBUG_TYPE_PORTABILITY: s = "portability"; break;
|
||||
case GL_DEBUG_TYPE_PERFORMANCE: s = "performance"; break;
|
||||
case GL_DEBUG_TYPE_MARKER: s = "marker"; break;
|
||||
case GL_DEBUG_TYPE_PUSH_GROUP: s = "push group"; break;
|
||||
case GL_DEBUG_TYPE_POP_GROUP: s = "pop group"; break;
|
||||
case GL_DEBUG_TYPE_OTHER: s = "other"; break;
|
||||
default: s.Format("%d", (int)type);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
FString FGLDebug::SeverityToString(GLenum severity)
|
||||
{
|
||||
FString s;
|
||||
switch (severity)
|
||||
{
|
||||
case GL_DEBUG_SEVERITY_LOW: s = "low severity"; break;
|
||||
case GL_DEBUG_SEVERITY_MEDIUM: s = "medium severity"; break;
|
||||
case GL_DEBUG_SEVERITY_HIGH: s = "high severity"; break;
|
||||
case GL_DEBUG_SEVERITY_NOTIFICATION: s = "notification"; break;
|
||||
default: s.Format("%d", (int)severity);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
#ifndef __GL_DEBUG_H
|
||||
#define __GL_DEBUG_H
|
||||
|
||||
#include <string.h>
|
||||
#include "gl_interface.h"
|
||||
#include "c_cvars.h"
|
||||
#include "r_defs.h"
|
||||
#include "v_video.h"
|
||||
|
||||
namespace OpenGLRenderer
|
||||
{
|
||||
|
||||
class FGLDebug
|
||||
{
|
||||
public:
|
||||
void Update();
|
||||
|
||||
static void LabelObject(GLenum type, GLuint handle, const char *name);
|
||||
static void LabelObjectPtr(void *ptr, const char *name);
|
||||
|
||||
static void PushGroup(const FString &name);
|
||||
static void PopGroup();
|
||||
|
||||
static bool HasDebugApi() { return (gl.flags & RFL_DEBUG) != 0; }
|
||||
|
||||
private:
|
||||
void SetupBreakpointMode();
|
||||
void UpdateLoggingLevel();
|
||||
void OutputMessageLog();
|
||||
|
||||
static bool IsFilteredByDebugLevel(GLenum severity);
|
||||
static void PrintMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message);
|
||||
|
||||
static void APIENTRY DebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam);
|
||||
|
||||
static FString SourceToString(GLenum source);
|
||||
static FString TypeToString(GLenum type);
|
||||
static FString SeverityToString(GLenum severity);
|
||||
|
||||
GLenum mCurrentLevel = 0;
|
||||
bool mBreakpointMode = false;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,30 +1,37 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2010-2016 Christoph Oelckers
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
/*
|
||||
** gl_framebuffer.cpp
|
||||
** Implementation of the non-hardware specific parts of the
|
||||
** OpenGL frame buffer
|
||||
**
|
||||
*/
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2010-2020 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "gl_system.h"
|
||||
#include "v_video.h"
|
||||
|
|
@ -35,8 +42,8 @@
|
|||
#include "gl_interface.h"
|
||||
#include "gl/system/gl_framebuffer.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/renderer/gl_renderbuffers.h"
|
||||
#include "gl/textures/gl_samplers.h"
|
||||
#include "gl_renderbuffers.h"
|
||||
#include "gl_samplers.h"
|
||||
#include "hwrenderer/utility/hw_clock.h"
|
||||
#include "hw_vrmodes.h"
|
||||
#include "hwrenderer/models/hw_models.h"
|
||||
|
|
@ -49,8 +56,10 @@
|
|||
#include "r_videoscale.h"
|
||||
#include "gl_buffers.h"
|
||||
#include "swrenderer/r_swscene.h"
|
||||
#include "gl_postprocessstate.h"
|
||||
|
||||
#include "flatvertices.h"
|
||||
#include "hw_cvars.h"
|
||||
|
||||
EXTERN_CVAR (Bool, vid_vsync)
|
||||
EXTERN_CVAR(Bool, r_drawvoxels)
|
||||
|
|
@ -412,7 +421,34 @@ void OpenGLFrameBuffer::SetSceneRenderTarget(bool useSSAO)
|
|||
|
||||
void OpenGLFrameBuffer::UpdateShadowMap()
|
||||
{
|
||||
GLRenderer->UpdateShadowMap();
|
||||
if (mShadowMap.PerformUpdate())
|
||||
{
|
||||
FGLDebug::PushGroup("ShadowMap");
|
||||
|
||||
FGLPostProcessState savedState;
|
||||
|
||||
static_cast<GLDataBuffer*>(screen->mShadowMap.mLightList)->BindBase();
|
||||
static_cast<GLDataBuffer*>(screen->mShadowMap.mNodesBuffer)->BindBase();
|
||||
static_cast<GLDataBuffer*>(screen->mShadowMap.mLinesBuffer)->BindBase();
|
||||
|
||||
GLRenderer->mBuffers->BindShadowMapFB();
|
||||
|
||||
GLRenderer->mShadowMapShader->Bind();
|
||||
GLRenderer->mShadowMapShader->Uniforms->ShadowmapQuality = gl_shadowmap_quality;
|
||||
GLRenderer->mShadowMapShader->Uniforms->NodesCount = screen->mShadowMap.NodesCount();
|
||||
GLRenderer->mShadowMapShader->Uniforms.SetData();
|
||||
static_cast<GLDataBuffer*>(GLRenderer->mShadowMapShader->Uniforms.GetBuffer())->BindBase();
|
||||
|
||||
glViewport(0, 0, gl_shadowmap_quality, 1024);
|
||||
GLRenderer->RenderScreenQuad();
|
||||
|
||||
const auto& viewport = screen->mScreenViewport;
|
||||
glViewport(viewport.left, viewport.top, viewport.width, viewport.height);
|
||||
|
||||
GLRenderer->mBuffers->BindShadowMapTexture(16);
|
||||
FGLDebug::PopGroup();
|
||||
screen->mShadowMap.FinishUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLFrameBuffer::WaitForCommands(bool finish)
|
||||
|
|
|
|||
|
|
@ -1,360 +0,0 @@
|
|||
/*
|
||||
** gl_hwtexture.cpp
|
||||
** GL texture abstraction
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2019 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
**
|
||||
*/
|
||||
|
||||
#include "gl_system.h"
|
||||
#include "templates.h"
|
||||
#include "c_cvars.h"
|
||||
#include "doomtype.h"
|
||||
#include "r_data/colormaps.h"
|
||||
#include "hw_material.h"
|
||||
|
||||
#include "gl_interface.h"
|
||||
#include "hw_cvars.h"
|
||||
#include "gl/system/gl_debug.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/renderer/gl_renderstate.h"
|
||||
#include "gl/textures/gl_samplers.h"
|
||||
|
||||
namespace OpenGLRenderer
|
||||
{
|
||||
|
||||
|
||||
TexFilter_s TexFilter[]={
|
||||
{GL_NEAREST, GL_NEAREST, false},
|
||||
{GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST, true},
|
||||
{GL_LINEAR, GL_LINEAR, false},
|
||||
{GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR, true},
|
||||
{GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, true},
|
||||
{GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST, true},
|
||||
{GL_LINEAR_MIPMAP_LINEAR, GL_NEAREST, true},
|
||||
};
|
||||
|
||||
int TexFormat[]={
|
||||
GL_RGBA8,
|
||||
GL_RGB5_A1,
|
||||
GL_RGBA4,
|
||||
GL_RGBA2,
|
||||
// [BB] Added compressed texture formats.
|
||||
GL_COMPRESSED_RGBA_ARB,
|
||||
GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
|
||||
GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
|
||||
GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
|
||||
};
|
||||
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Static texture data
|
||||
//
|
||||
//===========================================================================
|
||||
unsigned int FHardwareTexture::lastbound[FHardwareTexture::MAX_TEXTURES];
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Loads the texture image into the hardware
|
||||
//
|
||||
// NOTE: For some strange reason I was unable to find the source buffer
|
||||
// should be one line higher than the actual texture. I got extremely
|
||||
// strange crashes deep inside the GL driver when I didn't do it!
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
unsigned int FHardwareTexture::CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, const char *name)
|
||||
{
|
||||
int rh,rw;
|
||||
int texformat = GL_RGBA8;// TexFormat[gl_texture_format];
|
||||
bool deletebuffer=false;
|
||||
|
||||
/*
|
||||
if (forcenocompression)
|
||||
{
|
||||
texformat = GL_RGBA8;
|
||||
}
|
||||
*/
|
||||
bool firstCall = glTexID == 0;
|
||||
if (firstCall)
|
||||
{
|
||||
glGenTextures(1, &glTexID);
|
||||
}
|
||||
|
||||
int textureBinding = UINT_MAX;
|
||||
if (texunit == -1) glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding);
|
||||
if (texunit > 0) glActiveTexture(GL_TEXTURE0+texunit);
|
||||
if (texunit >= 0) lastbound[texunit] = glTexID;
|
||||
glBindTexture(GL_TEXTURE_2D, glTexID);
|
||||
|
||||
FGLDebug::LabelObject(GL_TEXTURE, glTexID, name);
|
||||
|
||||
rw = GetTexDimension(w);
|
||||
rh = GetTexDimension(h);
|
||||
if (glBufferID > 0)
|
||||
{
|
||||
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
|
||||
buffer = nullptr;
|
||||
}
|
||||
else if (!buffer)
|
||||
{
|
||||
// The texture must at least be initialized if no data is present.
|
||||
mipmapped = false;
|
||||
buffer=(unsigned char *)calloc(4,rw * (rh+1));
|
||||
deletebuffer=true;
|
||||
//texheight=-h;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rw < w || rh < h)
|
||||
{
|
||||
// The texture is larger than what the hardware can handle so scale it down.
|
||||
unsigned char * scaledbuffer=(unsigned char *)calloc(4,rw * (rh+1));
|
||||
if (scaledbuffer)
|
||||
{
|
||||
Resize(w, h, rw, rh, buffer, scaledbuffer);
|
||||
deletebuffer=true;
|
||||
buffer=scaledbuffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
// store the physical size.
|
||||
|
||||
int sourcetype;
|
||||
if (glTextureBytes > 0)
|
||||
{
|
||||
if (glTextureBytes < 4) glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
static const int ITypes[] = { GL_R8, GL_RG8, GL_RGB8, GL_RGBA8 };
|
||||
static const int STypes[] = { GL_RED, GL_RG, GL_BGR, GL_BGRA };
|
||||
|
||||
texformat = ITypes[glTextureBytes - 1];
|
||||
sourcetype = STypes[glTextureBytes - 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
sourcetype = GL_BGRA;
|
||||
}
|
||||
|
||||
if (!firstCall && glBufferID > 0)
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, rw, rh, sourcetype, GL_UNSIGNED_BYTE, buffer);
|
||||
else
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, texformat, rw, rh, 0, sourcetype, GL_UNSIGNED_BYTE, buffer);
|
||||
|
||||
if (deletebuffer && buffer) free(buffer);
|
||||
else if (glBufferID)
|
||||
{
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
}
|
||||
|
||||
if (mipmap && TexFilter[gl_texture_filter].mipmapping)
|
||||
{
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
mipmapped = true;
|
||||
}
|
||||
|
||||
if (texunit > 0) glActiveTexture(GL_TEXTURE0);
|
||||
else if (texunit == -1) glBindTexture(GL_TEXTURE_2D, textureBinding);
|
||||
return glTexID;
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
void FHardwareTexture::AllocateBuffer(int w, int h, int texelsize)
|
||||
{
|
||||
int rw = GetTexDimension(w);
|
||||
int rh = GetTexDimension(h);
|
||||
if (texelsize < 1 || texelsize > 4) texelsize = 4;
|
||||
glTextureBytes = texelsize;
|
||||
bufferpitch = w;
|
||||
if (rw == w || rh == h)
|
||||
{
|
||||
glGenBuffers(1, &glBufferID);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, glBufferID);
|
||||
glBufferData(GL_PIXEL_UNPACK_BUFFER, w*h*texelsize, nullptr, GL_STREAM_DRAW);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t *FHardwareTexture::MapBuffer()
|
||||
{
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, glBufferID);
|
||||
return (uint8_t*)glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Destroys the texture
|
||||
//
|
||||
//===========================================================================
|
||||
FHardwareTexture::~FHardwareTexture()
|
||||
{
|
||||
if (glTexID != 0) glDeleteTextures(1, &glTexID);
|
||||
if (glBufferID != 0) glDeleteBuffers(1, &glBufferID);
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Binds this patch
|
||||
//
|
||||
//===========================================================================
|
||||
unsigned int FHardwareTexture::Bind(int texunit, bool needmipmap)
|
||||
{
|
||||
if (glTexID != 0)
|
||||
{
|
||||
if (lastbound[texunit] == glTexID) return glTexID;
|
||||
lastbound[texunit] = glTexID;
|
||||
if (texunit != 0) glActiveTexture(GL_TEXTURE0 + texunit);
|
||||
glBindTexture(GL_TEXTURE_2D, glTexID);
|
||||
// Check if we need mipmaps on a texture that was creted without them.
|
||||
if (needmipmap && !mipmapped && TexFilter[gl_texture_filter].mipmapping)
|
||||
{
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
mipmapped = true;
|
||||
}
|
||||
if (texunit != 0) glActiveTexture(GL_TEXTURE0);
|
||||
return glTexID;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int FHardwareTexture::GetTextureHandle(int translation)
|
||||
{
|
||||
return glTexID;
|
||||
}
|
||||
|
||||
void FHardwareTexture::Unbind(int texunit)
|
||||
{
|
||||
if (lastbound[texunit] != 0)
|
||||
{
|
||||
if (texunit != 0) glActiveTexture(GL_TEXTURE0+texunit);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
if (texunit != 0) glActiveTexture(GL_TEXTURE0);
|
||||
lastbound[texunit] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void FHardwareTexture::UnbindAll()
|
||||
{
|
||||
for(int texunit = 0; texunit < 16; texunit++)
|
||||
{
|
||||
Unbind(texunit);
|
||||
}
|
||||
gl_RenderState.ClearLastMaterial();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Creates a depth buffer for this texture
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
int FHardwareTexture::GetDepthBuffer(int width, int height)
|
||||
{
|
||||
if (glDepthID == 0)
|
||||
{
|
||||
glGenRenderbuffers(1, &glDepthID);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, glDepthID);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8,
|
||||
GetTexDimension(width), GetTexDimension(height));
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
}
|
||||
return glDepthID;
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Binds this texture's surfaces to the current framrbuffer
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FHardwareTexture::BindToFrameBuffer(int width, int height)
|
||||
{
|
||||
width = GetTexDimension(width);
|
||||
height = GetTexDimension(height);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glTexID, 0);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, GetDepthBuffer(width, height));
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, GetDepthBuffer(width, height));
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Binds a texture to the renderer
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool FHardwareTexture::BindOrCreate(FTexture *tex, int texunit, int clampmode, int translation, int flags)
|
||||
{
|
||||
int usebright = false;
|
||||
|
||||
bool needmipmap = (clampmode <= CLAMP_XY);
|
||||
|
||||
// Bind it to the system.
|
||||
if (!Bind(texunit, needmipmap))
|
||||
{
|
||||
|
||||
int w = 0, h = 0;
|
||||
|
||||
// Create this texture
|
||||
|
||||
FTextureBuffer texbuffer;
|
||||
|
||||
if (!tex->isHardwareCanvas())
|
||||
{
|
||||
texbuffer = tex->CreateTexBuffer(translation, flags | CTF_ProcessData);
|
||||
w = texbuffer.mWidth;
|
||||
h = texbuffer.mHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
w = tex->GetWidth();
|
||||
h = tex->GetHeight();
|
||||
}
|
||||
if (!CreateTexture(texbuffer.mBuffer, w, h, texunit, needmipmap, "FHardwareTexture.BindOrCreate"))
|
||||
{
|
||||
// could not create texture
|
||||
return false;
|
||||
}
|
||||
}
|
||||
GLRenderer->mSamplerManager->Bind(texunit, clampmode, 255);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
|
||||
#ifndef __GLTEXTURE_H
|
||||
#define __GLTEXTURE_H
|
||||
|
||||
#ifdef LoadImage
|
||||
#undef LoadImage
|
||||
#endif
|
||||
|
||||
#define SHADED_TEXTURE -1
|
||||
#define DIRECT_PALETTE -2
|
||||
|
||||
#include "tarray.h"
|
||||
#include "gl_interface.h"
|
||||
#include "hw_ihwtexture.h"
|
||||
|
||||
class FCanvasTexture;
|
||||
|
||||
namespace OpenGLRenderer
|
||||
{
|
||||
|
||||
class FHardwareTexture : public IHardwareTexture
|
||||
{
|
||||
public:
|
||||
|
||||
static unsigned int lastbound[MAX_TEXTURES];
|
||||
|
||||
static int GetTexDimension(int value)
|
||||
{
|
||||
if (value > gl.max_texturesize) return gl.max_texturesize;
|
||||
return value;
|
||||
}
|
||||
|
||||
static void InitGlobalState() { for (int i = 0; i < MAX_TEXTURES; i++) lastbound[i] = 0; }
|
||||
|
||||
private:
|
||||
|
||||
bool forcenocompression;
|
||||
|
||||
unsigned int glTexID = 0;
|
||||
unsigned int glDepthID = 0; // only used by camera textures
|
||||
unsigned int glBufferID = 0;
|
||||
int glTextureBytes = 4;
|
||||
bool mipmapped = false;
|
||||
|
||||
int GetDepthBuffer(int w, int h);
|
||||
|
||||
public:
|
||||
FHardwareTexture(bool nocompress)
|
||||
{
|
||||
forcenocompression = nocompress;
|
||||
}
|
||||
|
||||
~FHardwareTexture();
|
||||
|
||||
static void Unbind(int texunit);
|
||||
static void UnbindAll();
|
||||
|
||||
void BindToFrameBuffer(int w, int h);
|
||||
|
||||
unsigned int Bind(int texunit, bool needmipmap);
|
||||
bool BindOrCreate(FTexture *tex, int texunit, int clampmode, int translation, int flags);
|
||||
|
||||
void AllocateBuffer(int w, int h, int texelsize);
|
||||
uint8_t *MapBuffer();
|
||||
|
||||
unsigned int CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, const char *name);
|
||||
unsigned int GetTextureHandle(int translation);
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
/*
|
||||
** gl_samplers.cpp
|
||||
**
|
||||
** Texture sampler handling
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2015-2019 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
#include "gl_system.h"
|
||||
#include "c_cvars.h"
|
||||
|
||||
#include "gl_interface.h"
|
||||
#include "hw_cvars.h"
|
||||
#include "gl/system/gl_debug.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl_samplers.h"
|
||||
#include "hw_material.h"
|
||||
|
||||
namespace OpenGLRenderer
|
||||
{
|
||||
|
||||
extern TexFilter_s TexFilter[];
|
||||
|
||||
|
||||
FSamplerManager::FSamplerManager()
|
||||
{
|
||||
glGenSamplers(7, mSamplers);
|
||||
SetTextureFilterMode();
|
||||
glSamplerParameteri(mSamplers[5], GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glSamplerParameteri(mSamplers[5], GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glSamplerParameterf(mSamplers[5], GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.f);
|
||||
glSamplerParameterf(mSamplers[4], GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.f);
|
||||
glSamplerParameterf(mSamplers[6], GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.f);
|
||||
|
||||
glSamplerParameteri(mSamplers[1], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(mSamplers[2], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(mSamplers[3], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(mSamplers[3], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(mSamplers[4], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(mSamplers[4], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
for (int i = 0; i < 7; i++)
|
||||
{
|
||||
FString name;
|
||||
name.Format("mSamplers[%d]", i);
|
||||
FGLDebug::LabelObject(GL_SAMPLER, mSamplers[i], name.GetChars());
|
||||
}
|
||||
}
|
||||
|
||||
FSamplerManager::~FSamplerManager()
|
||||
{
|
||||
UnbindAll();
|
||||
glDeleteSamplers(7, mSamplers);
|
||||
}
|
||||
|
||||
void FSamplerManager::UnbindAll()
|
||||
{
|
||||
for (int i = 0; i < FHardwareTexture::MAX_TEXTURES; i++)
|
||||
{
|
||||
glBindSampler(i, 0);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t FSamplerManager::Bind(int texunit, int num, int lastval)
|
||||
{
|
||||
unsigned int samp = mSamplers[num];
|
||||
glBindSampler(texunit, samp);
|
||||
return 255;
|
||||
}
|
||||
|
||||
|
||||
void FSamplerManager::SetTextureFilterMode()
|
||||
{
|
||||
UnbindAll();
|
||||
int filter = V_IsHardwareRenderer() ? gl_texture_filter : 0;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
glSamplerParameteri(mSamplers[i], GL_TEXTURE_MIN_FILTER, TexFilter[filter].minfilter);
|
||||
glSamplerParameteri(mSamplers[i], GL_TEXTURE_MAG_FILTER, TexFilter[filter].magfilter);
|
||||
glSamplerParameterf(mSamplers[i], GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_texture_filter_anisotropic);
|
||||
}
|
||||
glSamplerParameteri(mSamplers[4], GL_TEXTURE_MIN_FILTER, TexFilter[filter].magfilter);
|
||||
glSamplerParameteri(mSamplers[4], GL_TEXTURE_MAG_FILTER, TexFilter[filter].magfilter);
|
||||
glSamplerParameteri(mSamplers[6], GL_TEXTURE_MIN_FILTER, TexFilter[filter].magfilter);
|
||||
glSamplerParameteri(mSamplers[6], GL_TEXTURE_MAG_FILTER, TexFilter[filter].magfilter);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
#ifndef __GL_SAMPLERS_H
|
||||
#define __GL_SAMPLERS_H
|
||||
|
||||
#include "gl_hwtexture.h"
|
||||
|
||||
namespace OpenGLRenderer
|
||||
{
|
||||
|
||||
class FSamplerManager
|
||||
{
|
||||
// We need 6 different samplers: 4 for the different clamping modes,
|
||||
// one for 2D-textures and one for voxel textures
|
||||
unsigned int mSamplers[7];
|
||||
|
||||
void UnbindAll();
|
||||
|
||||
public:
|
||||
|
||||
FSamplerManager();
|
||||
~FSamplerManager();
|
||||
|
||||
uint8_t Bind(int texunit, int num, int lastval);
|
||||
void SetTextureFilterMode();
|
||||
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -30,6 +30,7 @@
|
|||
#include "i_time.h"
|
||||
#include "g_game.h"
|
||||
#include "v_text.h"
|
||||
#include "version.h"
|
||||
|
||||
#include "hwrenderer/utility/hw_clock.h"
|
||||
#include "hw_vrmodes.h"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue