Merge pull request #13582 from Zvork/scale

Render Scale Resolution applied only to 3D rendering not HUD
This commit is contained in:
John Conklin II 2018-07-12 10:56:03 -07:00 committed by GitHub
commit b59e9f9899
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 188 additions and 43 deletions

View file

@ -3267,13 +3267,22 @@ void Application::resizeGL() {
// Set the desired FBO texture size. If it hasn't changed, this does nothing.
// Otherwise, it must rebuild the FBOs
uvec2 framebufferSize = displayPlugin->getRecommendedRenderSize();
float renderResolutionScale = getRenderResolutionScale();
uvec2 renderSize = uvec2(vec2(framebufferSize) * renderResolutionScale);
uvec2 renderSize = uvec2(framebufferSize);
if (_renderResolution != renderSize) {
_renderResolution = renderSize;
DependencyManager::get<FramebufferCache>()->setFrameBufferSize(fromGlm(renderSize));
}
auto renderResolutionScale = getRenderResolutionScale();
if (displayPlugin->getRenderResolutionScale() != renderResolutionScale) {
auto renderConfig = _renderEngine->getConfiguration();
assert(renderConfig);
auto mainView = renderConfig->getConfig("RenderMainView.RenderDeferredTask");
assert(mainView);
mainView->setProperty("resolutionScale", renderResolutionScale);
displayPlugin->setRenderResolutionScale(renderResolutionScale);
}
// FIXME the aspect ratio for stereo displays is incorrect based on this.
float aspectRatio = displayPlugin->getRecommendedAspectRatio();
_myCamera.setProjection(glm::perspective(glm::radians(_fieldOfView.get()), aspectRatio,
@ -3285,7 +3294,6 @@ void Application::resizeGL() {
}
DependencyManager::get<OffscreenUi>()->resize(fromGlm(displayPlugin->getRecommendedUiSize()));
displayPlugin->setRenderResolutionScale(renderResolutionScale);
}
void Application::handleSandboxStatus(QNetworkReply* reply) {

View file

@ -102,7 +102,7 @@ void Application::paintGL() {
PerformanceTimer perfTimer("renderOverlay");
// NOTE: There is no batch associated with this renderArgs
// the ApplicationOverlay class assumes it's viewport is setup to be the device size
renderArgs._viewport = glm::ivec4(0, 0, getDeviceSize() * getRenderResolutionScale());
renderArgs._viewport = glm::ivec4(0, 0, getDeviceSize());
_applicationOverlay.renderOverlay(&renderArgs);
}
@ -118,7 +118,7 @@ void Application::paintGL() {
// Primary rendering pass
auto framebufferCache = DependencyManager::get<FramebufferCache>();
finalFramebufferSize = framebufferCache->getFrameBufferSize();
// Final framebuffer that will be handled to the display-plugin
// Final framebuffer that will be handed to the display-plugin
finalFramebuffer = framebufferCache->getFramebuffer();
}

View file

@ -179,7 +179,7 @@ static const auto DEPTH_FORMAT = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPT
void ApplicationOverlay::buildFramebufferObject() {
PROFILE_RANGE(app, __FUNCTION__);
auto uiSize = glm::uvec2(glm::vec2(qApp->getUiSize()) * qApp->getRenderResolutionScale());
auto uiSize = glm::uvec2(qApp->getUiSize());
if (!_overlayFramebuffer || uiSize != _overlayFramebuffer->getSize()) {
_overlayFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("ApplicationOverlay"));
}

View file

@ -116,7 +116,7 @@ void Overlays::renderHUD(RenderArgs* renderArgs) {
auto geometryCache = DependencyManager::get<GeometryCache>();
auto textureCache = DependencyManager::get<TextureCache>();
auto size = glm::uvec2(glm::vec2(qApp->getUiSize()) * qApp->getRenderResolutionScale());
auto size = glm::uvec2(qApp->getUiSize());
int width = size.x;
int height = size.y;
mat4 legacyProjection = glm::ortho<float>(0, width, height, 0, -1000, 1000);

View file

@ -275,7 +275,7 @@ bool CompositorHelper::getReticleOverDesktop() const {
// as being over the desktop.
if (isHMD()) {
QMutexLocker locker(&_reticleLock);
glm::vec2 maxOverlayPosition = glm::vec2(_currentDisplayPlugin->getRecommendedUiSize()) * _currentDisplayPlugin->getRenderResolutionScale();
glm::vec2 maxOverlayPosition = glm::vec2(_currentDisplayPlugin->getRecommendedUiSize());
static const glm::vec2 minOverlayPosition;
if (glm::any(glm::lessThan(_reticlePositionInHMD, minOverlayPosition)) ||
glm::any(glm::greaterThan(_reticlePositionInHMD, maxOverlayPosition))) {
@ -317,7 +317,7 @@ void CompositorHelper::sendFakeMouseEvent() {
void CompositorHelper::setReticlePosition(const glm::vec2& position, bool sendFakeEvent) {
if (isHMD()) {
glm::vec2 maxOverlayPosition = glm::vec2(_currentDisplayPlugin->getRecommendedUiSize()) * _currentDisplayPlugin->getRenderResolutionScale();
glm::vec2 maxOverlayPosition = glm::vec2(_currentDisplayPlugin->getRecommendedUiSize());
// FIXME don't allow negative mouseExtra
glm::vec2 mouseExtra = (MOUSE_EXTENTS_PIXELS - maxOverlayPosition) / 2.0f;
glm::vec2 minMouse = vec2(0) - mouseExtra;

View file

@ -888,7 +888,7 @@ OpenGLDisplayPlugin::~OpenGLDisplayPlugin() {
}
void OpenGLDisplayPlugin::updateCompositeFramebuffer() {
auto renderSize = glm::uvec2(glm::vec2(getRecommendedRenderSize()) * getRenderResolutionScale());
auto renderSize = glm::uvec2(getRecommendedRenderSize());
if (!_compositeFramebuffer || _compositeFramebuffer->getSize() != renderSize) {
_compositeFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("OpenGLDisplayPlugin::composite", gpu::Element::COLOR_RGBA_32, renderSize.x, renderSize.y));
}

View file

@ -393,34 +393,42 @@ graphics::MeshPointer DeferredLightingEffect::getSpotLightMesh() {
return _spotLightMesh;
}
void PreparePrimaryFramebuffer::run(const RenderContextPointer& renderContext, gpu::FramebufferPointer& primaryFramebuffer) {
gpu::FramebufferPointer PreparePrimaryFramebuffer::createFramebuffer(const char* name, const glm::uvec2& frameSize) {
gpu::FramebufferPointer framebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(name));
auto colorFormat = gpu::Element::COLOR_SRGBA_32;
auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR);
auto primaryColorTexture = gpu::Texture::createRenderBuffer(colorFormat, frameSize.x, frameSize.y, gpu::Texture::SINGLE_MIP, defaultSampler);
framebuffer->setRenderBuffer(0, primaryColorTexture);
auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); // Depth24_Stencil8 texel format
auto primaryDepthTexture = gpu::Texture::createRenderBuffer(depthFormat, frameSize.x, frameSize.y, gpu::Texture::SINGLE_MIP, defaultSampler);
framebuffer->setDepthStencilBuffer(primaryDepthTexture, depthFormat);
return framebuffer;
}
void PreparePrimaryFramebuffer::configure(const Config& config) {
_resolutionScale = config.resolutionScale;
}
void PreparePrimaryFramebuffer::run(const RenderContextPointer& renderContext, Output& primaryFramebuffer) {
glm::uvec2 frameSize(renderContext->args->_viewport.z, renderContext->args->_viewport.w);
glm::uvec2 scaledFrameSize(glm::vec2(frameSize) * _resolutionScale);
// Resizing framebuffers instead of re-building them seems to cause issues with threaded
// rendering
if (_primaryFramebuffer && _primaryFramebuffer->getSize() != frameSize) {
_primaryFramebuffer.reset();
if (!_primaryFramebuffer || _primaryFramebuffer->getSize() != scaledFrameSize) {
_primaryFramebuffer = createFramebuffer("deferredPrimary", scaledFrameSize);
}
if (!_primaryFramebuffer) {
_primaryFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("deferredPrimary"));
auto colorFormat = gpu::Element::COLOR_SRGBA_32;
auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT);
auto primaryColorTexture = gpu::Texture::createRenderBuffer(colorFormat, frameSize.x, frameSize.y, gpu::Texture::SINGLE_MIP, defaultSampler);
_primaryFramebuffer->setRenderBuffer(0, primaryColorTexture);
auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); // Depth24_Stencil8 texel format
auto primaryDepthTexture = gpu::Texture::createRenderBuffer(depthFormat, frameSize.x, frameSize.y, gpu::Texture::SINGLE_MIP, defaultSampler);
_primaryFramebuffer->setDepthStencilBuffer(primaryDepthTexture, depthFormat);
}
primaryFramebuffer = _primaryFramebuffer;
// Set viewport for the rest of the scaled passes
renderContext->args->_viewport.z = scaledFrameSize.x;
renderContext->args->_viewport.w = scaledFrameSize.y;
}
void PrepareDeferred::run(const RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) {

View file

@ -93,13 +93,34 @@ private:
friend class RenderDeferredCleanup;
};
class PreparePrimaryFramebufferConfig : public render::Job::Config {
Q_OBJECT
Q_PROPERTY(float resolutionScale MEMBER resolutionScale NOTIFY dirty)
public:
float resolutionScale{ 1.0f };
signals:
void dirty();
};
class PreparePrimaryFramebuffer {
public:
using JobModel = render::Job::ModelO<PreparePrimaryFramebuffer, gpu::FramebufferPointer>;
void run(const render::RenderContextPointer& renderContext, gpu::FramebufferPointer& primaryFramebuffer);
using Output = gpu::FramebufferPointer;
using Config = PreparePrimaryFramebufferConfig;
using JobModel = render::Job::ModelO<PreparePrimaryFramebuffer, Output, Config>;
PreparePrimaryFramebuffer(float resolutionScale = 1.0f) : _resolutionScale{resolutionScale} {}
void configure(const Config& config);
void run(const render::RenderContextPointer& renderContext, Output& primaryFramebuffer);
gpu::FramebufferPointer _primaryFramebuffer;
float _resolutionScale{ 1.0f };
private:
static gpu::FramebufferPointer createFramebuffer(const char* name, const glm::uvec2& size);
};
class PrepareDeferred {

View file

@ -26,6 +26,7 @@
#include <render/DrawStatus.h>
#include <render/DrawSceneOctree.h>
#include <render/BlurTask.h>
#include <render/ResampleTask.h>
#include "RenderHifi.h"
#include "RenderCommonTask.h"
@ -59,8 +60,14 @@ RenderDeferredTask::RenderDeferredTask()
{
}
void RenderDeferredTask::configure(const Config& config)
{
void RenderDeferredTask::configure(const Config& config) {
// Propagate resolution scale to sub jobs who need it
auto preparePrimaryBufferConfig = config.getConfig<PreparePrimaryFramebuffer>("PreparePrimaryBuffer");
auto upsamplePrimaryBufferConfig = config.getConfig<Upsample>("PrimaryBufferUpscale");
assert(preparePrimaryBufferConfig);
assert(upsamplePrimaryBufferConfig);
preparePrimaryBufferConfig->setProperty("resolutionScale", config.resolutionScale);
upsamplePrimaryBufferConfig->setProperty("factor", 1.0f / config.resolutionScale);
}
const render::Varying RenderDeferredTask::addSelectItemJobs(JobModel& task, const char* selectionName,
@ -97,23 +104,22 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
const auto jitter = task.addJob<JitterSample>("JitterCam");
// Prepare deferred, generate the shared Deferred Frame Transform
// GPU jobs: Start preparing the primary, deferred and lighting buffer
const auto scaledPrimaryFramebuffer = task.addJob<PreparePrimaryFramebuffer>("PreparePrimaryBuffer");
// Prepare deferred, generate the shared Deferred Frame Transform. Only valid with the scaled frame buffer
const auto deferredFrameTransform = task.addJob<GenerateDeferredFrameTransform>("DeferredFrameTransform", jitter);
const auto lightingModel = task.addJob<MakeLightingModel>("LightingModel");
// GPU jobs: Start preparing the primary, deferred and lighting buffer
const auto primaryFramebuffer = task.addJob<PreparePrimaryFramebuffer>("PreparePrimaryBuffer");
const auto opaqueRangeTimer = task.addJob<BeginGPURangeTimer>("BeginOpaqueRangeTimer", "DrawOpaques");
const auto prepareDeferredInputs = PrepareDeferred::Inputs(primaryFramebuffer, lightingModel).asVarying();
const auto prepareDeferredInputs = PrepareDeferred::Inputs(scaledPrimaryFramebuffer, lightingModel).asVarying();
const auto prepareDeferredOutputs = task.addJob<PrepareDeferred>("PrepareDeferred", prepareDeferredInputs);
const auto deferredFramebuffer = prepareDeferredOutputs.getN<PrepareDeferred::Outputs>(0);
const auto lightingFramebuffer = prepareDeferredOutputs.getN<PrepareDeferred::Outputs>(1);
// draw a stencil mask in hidden regions of the framebuffer.
task.addJob<PrepareStencil>("PrepareStencil", primaryFramebuffer);
task.addJob<PrepareStencil>("PrepareStencil", scaledPrimaryFramebuffer);
// Render opaque objects in DeferredBuffer
const auto opaqueInputs = DrawStateSortDeferred::Inputs(opaques, lightingModel, jitter).asVarying();
@ -223,7 +229,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
task.addJob<Bloom>("Bloom", bloomInputs);
// Lighting Buffer ready for tone mapping
const auto toneMappingInputs = ToneMappingDeferred::Inputs(lightingFramebuffer, primaryFramebuffer).asVarying();
const auto toneMappingInputs = ToneMappingDeferred::Inputs(lightingFramebuffer, scaledPrimaryFramebuffer).asVarying();
task.addJob<ToneMappingDeferred>("ToneMapping", toneMappingInputs);
{ // Debug the bounds of the rendered items, still look at the zbuffer
@ -284,6 +290,9 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
task.addJob<DebugZoneLighting>("DrawZoneStack", deferredFrameTransform);
}
// Upscale to finale resolution
const auto primaryFramebuffer = task.addJob<render::Upsample>("PrimaryBufferUpscale", scaledPrimaryFramebuffer);
// Composite the HUD and HUD overlays
task.addJob<CompositeHUD>("HUD");

View file

@ -105,11 +105,13 @@ class RenderDeferredTaskConfig : public render::Task::Config {
Q_OBJECT
Q_PROPERTY(float fadeScale MEMBER fadeScale NOTIFY dirty)
Q_PROPERTY(float fadeDuration MEMBER fadeDuration NOTIFY dirty)
Q_PROPERTY(float resolutionScale MEMBER resolutionScale NOTIFY dirty)
Q_PROPERTY(bool debugFade MEMBER debugFade NOTIFY dirty)
Q_PROPERTY(float debugFadePercent MEMBER debugFadePercent NOTIFY dirty)
public:
float fadeScale{ 0.5f };
float fadeDuration{ 3.0f };
float resolutionScale{ 1.f };
float debugFadePercent{ 0.f };
bool debugFade{ false };

View file

@ -81,3 +81,69 @@ void HalfDownsample::run(const RenderContextPointer& renderContext, const gpu::F
batch.draw(gpu::TRIANGLE_STRIP, 4);
});
}
gpu::PipelinePointer Upsample::_pipeline;
void Upsample::configure(const Config& config) {
_factor = config.factor;
}
gpu::FramebufferPointer Upsample::getResampledFrameBuffer(const gpu::FramebufferPointer& sourceFramebuffer) {
if (_factor == 1.0f) {
return sourceFramebuffer;
}
auto resampledFramebufferSize = glm::uvec2(glm::vec2(sourceFramebuffer->getSize()) * _factor);
if (!_destinationFrameBuffer || resampledFramebufferSize != _destinationFrameBuffer->getSize()) {
_destinationFrameBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("UpsampledOutput"));
auto sampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR);
auto target = gpu::Texture::createRenderBuffer(sourceFramebuffer->getRenderBuffer(0)->getTexelFormat(), resampledFramebufferSize.x, resampledFramebufferSize.y, gpu::Texture::SINGLE_MIP, sampler);
_destinationFrameBuffer->setRenderBuffer(0, target);
}
return _destinationFrameBuffer;
}
void Upsample::run(const RenderContextPointer& renderContext, const gpu::FramebufferPointer& sourceFramebuffer, gpu::FramebufferPointer& resampledFrameBuffer) {
assert(renderContext->args);
assert(renderContext->args->hasViewFrustum());
RenderArgs* args = renderContext->args;
resampledFrameBuffer = getResampledFrameBuffer(sourceFramebuffer);
if (resampledFrameBuffer != sourceFramebuffer) {
if (!_pipeline) {
auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS();
auto ps = gpu::StandardShaderLib::getDrawTextureOpaquePS();
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
gpu::Shader::BindingSet slotBindings;
gpu::Shader::makeProgram(*program, slotBindings);
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
state->setDepthTest(gpu::State::DepthTest(false, false));
_pipeline = gpu::Pipeline::create(program, state);
}
const auto bufferSize = resampledFrameBuffer->getSize();
glm::ivec4 viewport{ 0, 0, bufferSize.x, bufferSize.y };
gpu::doInBatch("Upsample::run", args->_context, [&](gpu::Batch& batch) {
batch.enableStereo(false);
batch.setFramebuffer(resampledFrameBuffer);
batch.setViewportTransform(viewport);
batch.setProjectionTransform(glm::mat4());
batch.resetViewTransform();
batch.setPipeline(_pipeline);
batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(bufferSize, viewport));
batch.setResourceTexture(0, sourceFramebuffer->getRenderBuffer(0));
batch.draw(gpu::TRIANGLE_STRIP, 4);
});
// Set full final viewport
args->_viewport = viewport;
}
}

View file

@ -36,6 +36,37 @@ namespace render {
gpu::FramebufferPointer getResampledFrameBuffer(const gpu::FramebufferPointer& sourceFramebuffer);
};
class UpsampleConfig : public render::Job::Config {
Q_OBJECT
Q_PROPERTY(float factor MEMBER factor NOTIFY dirty)
public:
float factor{ 1.0f };
signals:
void dirty();
};
class Upsample {
public:
using Config = UpsampleConfig;
using JobModel = Job::ModelIO<Upsample, gpu::FramebufferPointer, gpu::FramebufferPointer, Config>;
Upsample(float factor = 2.0f) : _factor{ factor } {}
void configure(const Config& config);
void run(const RenderContextPointer& renderContext, const gpu::FramebufferPointer& sourceFramebuffer, gpu::FramebufferPointer& resampledFrameBuffer);
protected:
static gpu::PipelinePointer _pipeline;
gpu::FramebufferPointer _destinationFrameBuffer;
float _factor{ 2.0f };
gpu::FramebufferPointer getResampledFrameBuffer(const gpu::FramebufferPointer& sourceFramebuffer);
};
}
#endif // hifi_render_ResampleTask_h