|
@@ -37,6 +37,7 @@
|
|
|
#include "../../Graphics/ShaderProgram.h"
|
|
#include "../../Graphics/ShaderProgram.h"
|
|
|
#include "../../Graphics/ShaderVariation.h"
|
|
#include "../../Graphics/ShaderVariation.h"
|
|
|
#include "../../Graphics/Texture2D.h"
|
|
#include "../../Graphics/Texture2D.h"
|
|
|
|
|
+#include "../../Graphics/TextureCube.h"
|
|
|
#include "../../Graphics/VertexBuffer.h"
|
|
#include "../../Graphics/VertexBuffer.h"
|
|
|
#include "../../IO/File.h"
|
|
#include "../../IO/File.h"
|
|
|
#include "../../IO/Log.h"
|
|
#include "../../IO/Log.h"
|
|
@@ -748,6 +749,130 @@ bool Graphics::ResolveToTexture(Texture2D* destination, const IntRect& viewport)
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+bool Graphics::ResolveToTexture(Texture2D* texture)
|
|
|
|
|
+{
|
|
|
|
|
+#ifndef GL_ES_VERSION_2_0
|
|
|
|
|
+ if (!texture)
|
|
|
|
|
+ return false;
|
|
|
|
|
+ RenderSurface* surface = texture->GetRenderSurface();
|
|
|
|
|
+ if (!surface || !surface->GetRenderBuffer())
|
|
|
|
|
+ return false;
|
|
|
|
|
+
|
|
|
|
|
+ URHO3D_PROFILE(ResolveToTexture);
|
|
|
|
|
+
|
|
|
|
|
+ texture->SetResolveDirty(false);
|
|
|
|
|
+ surface->SetResolveDirty(false);
|
|
|
|
|
+
|
|
|
|
|
+ // Use separate FBOs for resolve to not disturb the currently set rendertarget(s)
|
|
|
|
|
+ if (!impl_->resolveSrcFBO_)
|
|
|
|
|
+ impl_->resolveSrcFBO_ = CreateFramebuffer();
|
|
|
|
|
+ if (!impl_->resolveDestFBO_)
|
|
|
|
|
+ impl_->resolveDestFBO_ = CreateFramebuffer();
|
|
|
|
|
+
|
|
|
|
|
+ if (!gl3Support)
|
|
|
|
|
+ {
|
|
|
|
|
+ glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, impl_->resolveSrcFBO_);
|
|
|
|
|
+ glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT,
|
|
|
|
|
+ surface->GetRenderBuffer());
|
|
|
|
|
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, impl_->resolveDestFBO_);
|
|
|
|
|
+ glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texture->GetGPUObjectName(),
|
|
|
|
|
+ 0);
|
|
|
|
|
+ glBlitFramebufferEXT(0, 0, texture->GetWidth(), texture->GetHeight(), 0, 0, texture->GetWidth(), texture->GetHeight(),
|
|
|
|
|
+ GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
|
|
|
|
+ glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
|
|
|
|
|
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, impl_->resolveSrcFBO_);
|
|
|
|
|
+ glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, surface->GetRenderBuffer());
|
|
|
|
|
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, impl_->resolveDestFBO_);
|
|
|
|
|
+ glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->GetGPUObjectName(), 0);
|
|
|
|
|
+ glBlitFramebuffer(0, 0, texture->GetWidth(), texture->GetHeight(), 0, 0, texture->GetWidth(), texture->GetHeight(),
|
|
|
|
|
+ GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
|
|
|
|
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
|
|
|
|
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Restore previously bound FBO
|
|
|
|
|
+ BindFramebuffer(impl_->boundFBO_);
|
|
|
|
|
+ return true;
|
|
|
|
|
+#else
|
|
|
|
|
+ // Not supported on GLES
|
|
|
|
|
+ return false;
|
|
|
|
|
+#endif
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+bool Graphics::ResolveToTexture(TextureCube* texture)
|
|
|
|
|
+{
|
|
|
|
|
+#ifndef GL_ES_VERSION_2_0
|
|
|
|
|
+ if (!texture)
|
|
|
|
|
+ return false;
|
|
|
|
|
+
|
|
|
|
|
+ URHO3D_PROFILE(ResolveToTexture);
|
|
|
|
|
+
|
|
|
|
|
+ texture->SetResolveDirty(false);
|
|
|
|
|
+
|
|
|
|
|
+ // Use separate FBOs for resolve to not disturb the currently set rendertarget(s)
|
|
|
|
|
+ if (!impl_->resolveSrcFBO_)
|
|
|
|
|
+ impl_->resolveSrcFBO_ = CreateFramebuffer();
|
|
|
|
|
+ if (!impl_->resolveDestFBO_)
|
|
|
|
|
+ impl_->resolveDestFBO_ = CreateFramebuffer();
|
|
|
|
|
+
|
|
|
|
|
+ if (!gl3Support)
|
|
|
|
|
+ {
|
|
|
|
|
+ for (unsigned i = 0; i < MAX_CUBEMAP_FACES; ++i)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Resolve only the surface(s) that were actually rendered to
|
|
|
|
|
+ RenderSurface* surface = texture->GetRenderSurface((CubeMapFace)i);
|
|
|
|
|
+ if (!surface->IsResolveDirty())
|
|
|
|
|
+ continue;
|
|
|
|
|
+
|
|
|
|
|
+ surface->SetResolveDirty(false);
|
|
|
|
|
+ glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, impl_->resolveSrcFBO_);
|
|
|
|
|
+ glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT,
|
|
|
|
|
+ surface->GetRenderBuffer());
|
|
|
|
|
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, impl_->resolveDestFBO_);
|
|
|
|
|
+ glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
|
|
|
|
|
+ texture->GetGPUObjectName(), 0);
|
|
|
|
|
+ glBlitFramebufferEXT(0, 0, texture->GetWidth(), texture->GetHeight(), 0, 0, texture->GetWidth(), texture->GetHeight(),
|
|
|
|
|
+ GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
|
|
|
|
|
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ for (unsigned i = 0; i < MAX_CUBEMAP_FACES; ++i)
|
|
|
|
|
+ {
|
|
|
|
|
+ RenderSurface* surface = texture->GetRenderSurface((CubeMapFace)i);
|
|
|
|
|
+ if (!surface->IsResolveDirty())
|
|
|
|
|
+ continue;
|
|
|
|
|
+
|
|
|
|
|
+ surface->SetResolveDirty(false);
|
|
|
|
|
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, impl_->resolveSrcFBO_);
|
|
|
|
|
+ glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, surface->GetRenderBuffer());
|
|
|
|
|
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, impl_->resolveDestFBO_);
|
|
|
|
|
+ glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
|
|
|
|
|
+ texture->GetGPUObjectName(), 0);
|
|
|
|
|
+ glBlitFramebuffer(0, 0, texture->GetWidth(), texture->GetHeight(), 0, 0, texture->GetWidth(), texture->GetHeight(),
|
|
|
|
|
+ GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
|
|
|
|
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Restore previously bound FBO
|
|
|
|
|
+ BindFramebuffer(impl_->boundFBO_);
|
|
|
|
|
+ return true;
|
|
|
|
|
+#else
|
|
|
|
|
+ // Not supported on GLES
|
|
|
|
|
+ return false;
|
|
|
|
|
+#endif
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
void Graphics::Draw(PrimitiveType type, unsigned vertexStart, unsigned vertexCount)
|
|
void Graphics::Draw(PrimitiveType type, unsigned vertexStart, unsigned vertexCount)
|
|
|
{
|
|
{
|
|
|
if (!vertexCount)
|
|
if (!vertexCount)
|
|
@@ -1127,7 +1252,6 @@ void Graphics::SetShaderParameter(StringHash param, float value)
|
|
|
void Graphics::SetShaderParameter(StringHash param, bool value)
|
|
void Graphics::SetShaderParameter(StringHash param, bool value)
|
|
|
{
|
|
{
|
|
|
// \todo Not tested
|
|
// \todo Not tested
|
|
|
-
|
|
|
|
|
if (impl_->shaderProgram_)
|
|
if (impl_->shaderProgram_)
|
|
|
{
|
|
{
|
|
|
const ShaderParameter* info = impl_->shaderProgram_->GetParameter(param);
|
|
const ShaderParameter* info = impl_->shaderProgram_->GetParameter(param);
|
|
@@ -1441,6 +1565,17 @@ void Graphics::SetTexture(unsigned index, Texture* texture)
|
|
|
{
|
|
{
|
|
|
if (renderTargets_[0] && renderTargets_[0]->GetParentTexture() == texture)
|
|
if (renderTargets_[0] && renderTargets_[0]->GetParentTexture() == texture)
|
|
|
texture = texture->GetBackupTexture();
|
|
texture = texture->GetBackupTexture();
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ // Resolve multisampled texture now as necessary
|
|
|
|
|
+ if (texture->GetMultiSample() > 1 && texture->GetAutoResolve() && texture->IsResolveDirty())
|
|
|
|
|
+ {
|
|
|
|
|
+ if (texture->GetType() == Texture2D::GetTypeStatic())
|
|
|
|
|
+ ResolveToTexture(static_cast<Texture2D*>(texture));
|
|
|
|
|
+ if (texture->GetType() == TextureCube::GetTypeStatic())
|
|
|
|
|
+ ResolveToTexture(static_cast<TextureCube*>(texture));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (textures_[index] != texture)
|
|
if (textures_[index] != texture)
|
|
@@ -1573,6 +1708,13 @@ void Graphics::SetRenderTarget(unsigned index, RenderSurface* renderTarget)
|
|
|
if (textures_[i] == parentTexture)
|
|
if (textures_[i] == parentTexture)
|
|
|
SetTexture(i, textures_[i]->GetBackupTexture());
|
|
SetTexture(i, textures_[i]->GetBackupTexture());
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ // If multisampled, mark the texture & surface needing resolve
|
|
|
|
|
+ if (parentTexture->GetMultiSample() > 1 && parentTexture->GetAutoResolve())
|
|
|
|
|
+ {
|
|
|
|
|
+ parentTexture->SetResolveDirty(true);
|
|
|
|
|
+ renderTarget->SetResolveDirty(true);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
impl_->fboDirty_ = true;
|
|
impl_->fboDirty_ = true;
|
|
@@ -1592,7 +1734,9 @@ void Graphics::SetDepthStencil(RenderSurface* depthStencil)
|
|
|
{
|
|
{
|
|
|
// If we are using a rendertarget texture, it is required in OpenGL to also have an own depth-stencil
|
|
// If we are using a rendertarget texture, it is required in OpenGL to also have an own depth-stencil
|
|
|
// Create a new depth-stencil texture as necessary to be able to provide similar behaviour as Direct3D9
|
|
// Create a new depth-stencil texture as necessary to be able to provide similar behaviour as Direct3D9
|
|
|
- if (renderTargets_[0] && !depthStencil)
|
|
|
|
|
|
|
+ // Only do this for non-multisampled rendertargets; when using multisampled target a similarly multisampled
|
|
|
|
|
+ // depth-stencil should also be provided (backbuffer depth isn't compatible)
|
|
|
|
|
+ if (renderTargets_[0] && renderTargets_[0]->GetMultiSample() == 1 && !depthStencil)
|
|
|
{
|
|
{
|
|
|
int width = renderTargets_[0]->GetWidth();
|
|
int width = renderTargets_[0]->GetWidth();
|
|
|
int height = renderTargets_[0]->GetHeight();
|
|
int height = renderTargets_[0]->GetHeight();
|
|
@@ -2171,7 +2315,7 @@ void Graphics::CleanupRenderSurface(RenderSurface* surface)
|
|
|
BindFramebuffer(i->second_.fbo_);
|
|
BindFramebuffer(i->second_.fbo_);
|
|
|
currentFBO = i->second_.fbo_;
|
|
currentFBO = i->second_.fbo_;
|
|
|
}
|
|
}
|
|
|
- BindColorAttachment(j, GL_TEXTURE_2D, 0);
|
|
|
|
|
|
|
+ BindColorAttachment(j, GL_TEXTURE_2D, 0, false);
|
|
|
i->second_.colorAttachments_[j] = 0;
|
|
i->second_.colorAttachments_[j] = 0;
|
|
|
// Mark drawbuffer bits to need recalculation
|
|
// Mark drawbuffer bits to need recalculation
|
|
|
i->second_.drawBuffers_ = M_MAX_UNSIGNED;
|
|
i->second_.drawBuffers_ = M_MAX_UNSIGNED;
|
|
@@ -2827,25 +2971,38 @@ void Graphics::PrepareDraw()
|
|
|
{
|
|
{
|
|
|
Texture* texture = renderTargets_[j]->GetParentTexture();
|
|
Texture* texture = renderTargets_[j]->GetParentTexture();
|
|
|
|
|
|
|
|
- // If texture's parameters are dirty, update before attaching
|
|
|
|
|
- if (texture->GetParametersDirty())
|
|
|
|
|
|
|
+ // Bind either a renderbuffer or texture, depending on what is available
|
|
|
|
|
+ unsigned renderBufferID = renderTargets_[j]->GetRenderBuffer();
|
|
|
|
|
+ if (!renderBufferID)
|
|
|
{
|
|
{
|
|
|
- SetTextureForUpdate(texture);
|
|
|
|
|
- texture->UpdateParameters();
|
|
|
|
|
- SetTexture(0, 0);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // If texture's parameters are dirty, update before attaching
|
|
|
|
|
+ if (texture->GetParametersDirty())
|
|
|
|
|
+ {
|
|
|
|
|
+ SetTextureForUpdate(texture);
|
|
|
|
|
+ texture->UpdateParameters();
|
|
|
|
|
+ SetTexture(0, 0);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- if (i->second_.colorAttachments_[j] != renderTargets_[j])
|
|
|
|
|
|
|
+ if (i->second_.colorAttachments_[j] != renderTargets_[j])
|
|
|
|
|
+ {
|
|
|
|
|
+ BindColorAttachment(j, renderTargets_[j]->GetTarget(), texture->GetGPUObjectName(), false);
|
|
|
|
|
+ i->second_.colorAttachments_[j] = renderTargets_[j];
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
{
|
|
{
|
|
|
- BindColorAttachment(j, renderTargets_[j]->GetTarget(), texture->GetGPUObjectName());
|
|
|
|
|
- i->second_.colorAttachments_[j] = renderTargets_[j];
|
|
|
|
|
|
|
+ if (i->second_.colorAttachments_[j] != renderTargets_[j])
|
|
|
|
|
+ {
|
|
|
|
|
+ BindColorAttachment(j, renderTargets_[j]->GetTarget(), renderBufferID, true);
|
|
|
|
|
+ i->second_.colorAttachments_[j] = renderTargets_[j];
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
|
if (i->second_.colorAttachments_[j])
|
|
if (i->second_.colorAttachments_[j])
|
|
|
{
|
|
{
|
|
|
- BindColorAttachment(j, GL_TEXTURE_2D, 0);
|
|
|
|
|
|
|
+ BindColorAttachment(j, GL_TEXTURE_2D, 0, false);
|
|
|
i->second_.colorAttachments_[j] = 0;
|
|
i->second_.colorAttachments_[j] = 0;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -3009,9 +3166,18 @@ void Graphics::CleanupFramebuffers()
|
|
|
for (HashMap<unsigned long long, FrameBufferObject>::Iterator i = impl_->frameBuffers_.Begin();
|
|
for (HashMap<unsigned long long, FrameBufferObject>::Iterator i = impl_->frameBuffers_.Begin();
|
|
|
i != impl_->frameBuffers_.End(); ++i)
|
|
i != impl_->frameBuffers_.End(); ++i)
|
|
|
DeleteFramebuffer(i->second_.fbo_);
|
|
DeleteFramebuffer(i->second_.fbo_);
|
|
|
|
|
+
|
|
|
|
|
+ if (impl_->resolveSrcFBO_)
|
|
|
|
|
+ DeleteFramebuffer(impl_->resolveSrcFBO_);
|
|
|
|
|
+ if (impl_->resolveDestFBO_)
|
|
|
|
|
+ DeleteFramebuffer(impl_->resolveDestFBO_);
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
|
|
+ {
|
|
|
impl_->boundFBO_ = 0;
|
|
impl_->boundFBO_ = 0;
|
|
|
|
|
+ impl_->resolveSrcFBO_ = 0;
|
|
|
|
|
+ impl_->resolveDestFBO_ = 0;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
impl_->frameBuffers_.Clear();
|
|
impl_->frameBuffers_.Clear();
|
|
|
}
|
|
}
|
|
@@ -3138,14 +3304,27 @@ void Graphics::BindFramebuffer(unsigned fbo)
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
|
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-void Graphics::BindColorAttachment(unsigned index, unsigned target, unsigned object)
|
|
|
|
|
|
|
+void Graphics::BindColorAttachment(unsigned index, unsigned target, unsigned object, bool isRenderBuffer)
|
|
|
{
|
|
{
|
|
|
|
|
+ if (!object)
|
|
|
|
|
+ isRenderBuffer = false;
|
|
|
|
|
+
|
|
|
#ifndef GL_ES_VERSION_2_0
|
|
#ifndef GL_ES_VERSION_2_0
|
|
|
if (!gl3Support)
|
|
if (!gl3Support)
|
|
|
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + index, target, object, 0);
|
|
|
|
|
|
|
+ {
|
|
|
|
|
+ if (!isRenderBuffer)
|
|
|
|
|
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + index, target, object, 0);
|
|
|
|
|
+ else
|
|
|
|
|
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + index, GL_RENDERBUFFER_EXT, object);
|
|
|
|
|
+ }
|
|
|
else
|
|
else
|
|
|
#endif
|
|
#endif
|
|
|
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + index, target, object, 0);
|
|
|
|
|
|
|
+ {
|
|
|
|
|
+ if (!isRenderBuffer)
|
|
|
|
|
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + index, target, object, 0);
|
|
|
|
|
+ else
|
|
|
|
|
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + index, GL_RENDERBUFFER, object);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void Graphics::BindDepthAttachment(unsigned object, bool isRenderBuffer)
|
|
void Graphics::BindDepthAttachment(unsigned object, bool isRenderBuffer)
|