Browse Source

Initial multisample support for Texture2D on Direct3D9.

Lasse Öörni 9 years ago
parent
commit
56edbef9d6

+ 1 - 1
Source/Urho3D/AngelScript/GraphicsAPI.cpp

@@ -513,7 +513,7 @@ static void RegisterTextures(asIScriptEngine* engine)
     engine->RegisterObjectMethod("RenderSurface", "RenderSurface@+ get_linkedDepthStencil() const", asMETHOD(RenderSurface, GetLinkedDepthStencil), asCALL_THISCALL);
     engine->RegisterObjectMethod("RenderSurface", "RenderSurface@+ get_linkedDepthStencil() const", asMETHOD(RenderSurface, GetLinkedDepthStencil), asCALL_THISCALL);
 
 
     RegisterTexture<Texture2D>(engine, "Texture2D");
     RegisterTexture<Texture2D>(engine, "Texture2D");
-    engine->RegisterObjectMethod("Texture2D", "bool SetSize(int, int, uint, TextureUsage usage = TEXTURE_STATIC)", asMETHOD(Texture2D, SetSize), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Texture2D", "bool SetSize(int, int, uint, TextureUsage usage = TEXTURE_STATIC, int multiSample = 1, bool autoResolve = true)", asMETHOD(Texture2D, SetSize), asCALL_THISCALL);
     engine->RegisterObjectMethod("Texture2D", "bool SetData(Image@+, bool useAlpha = false)", asMETHODPR(Texture2D, SetData, (Image*, bool), bool), asCALL_THISCALL);
     engine->RegisterObjectMethod("Texture2D", "bool SetData(Image@+, bool useAlpha = false)", asMETHODPR(Texture2D, SetData, (Image*, bool), bool), asCALL_THISCALL);
     engine->RegisterObjectMethod("Texture2D", "RenderSurface@+ get_renderSurface() const", asMETHOD(Texture2D, GetRenderSurface), asCALL_THISCALL);
     engine->RegisterObjectMethod("Texture2D", "RenderSurface@+ get_renderSurface() const", asMETHOD(Texture2D, GetRenderSurface), asCALL_THISCALL);
     engine->RegisterObjectMethod("Texture2D", "Image@+ GetImage() const", asFUNCTION(Texture2DGetImage), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("Texture2D", "Image@+ GetImage() const", asFUNCTION(Texture2DGetImage), asCALL_CDECL_OBJLAST);

+ 52 - 7
Source/Urho3D/Graphics/Direct3D9/D3D9Graphics.cpp

@@ -409,8 +409,7 @@ bool Graphics::SetMode(int width, int height, bool fullscreen, bool borderless,
     // Fall back to non-multisampled if unsupported multisampling mode
     // Fall back to non-multisampled if unsupported multisampling mode
     if (multiSample > 1)
     if (multiSample > 1)
     {
     {
-        if (FAILED(impl_->interface_->CheckDeviceMultiSampleType(impl_->adapter_, impl_->deviceType_, fullscreenFormat, FALSE,
-            (D3DMULTISAMPLE_TYPE)multiSample, NULL)))
+        if (!impl_->CheckMultiSampleSupport(fullscreenFormat, multiSample))
             multiSample = 1;
             multiSample = 1;
     }
     }
 
 
@@ -830,6 +829,40 @@ bool Graphics::ResolveToTexture(Texture2D* destination, const IntRect& viewport)
         return true;
         return true;
 }
 }
 
 
+bool Graphics::ResolveToTexture(Texture2D* texture)
+{
+    if (!texture || !texture->GetRenderSurface() || !texture->GetGPUObject() || texture->GetMultiSample() < 2)
+        return false;
+
+    URHO3D_PROFILE(ResolveToTexture);
+
+    RECT rect;
+    rect.left = 0;
+    rect.top = 0;
+    rect.right = texture->GetWidth();
+    rect.bottom = texture->GetHeight();
+
+    IDirect3DSurface9* srcSurface = (IDirect3DSurface9*)texture->GetRenderSurface()->GetSurface();
+    IDirect3DTexture9* destTexture = (IDirect3DTexture9*)texture->GetGPUObject();
+    IDirect3DSurface9* destSurface = 0;
+    HRESULT hr = destTexture->GetSurfaceLevel(0, &destSurface);
+    if (FAILED(hr))
+    {
+        URHO3D_LOGD3DERROR("Failed to get destination surface for resolve", hr);
+        return false;
+    }
+
+    hr = impl_->device_->StretchRect(srcSurface, &rect, destSurface, &rect, D3DTEXF_NONE);
+    URHO3D_SAFE_RELEASE(destSurface);
+    if (FAILED(hr))
+    {
+        URHO3D_LOGD3DERROR("Failed to resolve to texture", hr);
+        return false;
+    }
+    else
+        return true;
+}
+
 void Graphics::Draw(PrimitiveType type, unsigned vertexStart, unsigned vertexCount)
 void Graphics::Draw(PrimitiveType type, unsigned vertexStart, unsigned vertexCount)
 {
 {
     if (!vertexCount)
     if (!vertexCount)
@@ -1368,11 +1401,21 @@ void Graphics::SetTexture(unsigned index, Texture* texture)
     if (index >= MAX_TEXTURE_UNITS)
     if (index >= MAX_TEXTURE_UNITS)
         return;
         return;
 
 
-    // Check if texture is currently bound as a rendertarget. In that case, use its backup texture, or blank if not defined
     if (texture)
     if (texture)
     {
     {
+        // Check if texture is currently bound as a rendertarget. In that case, use its backup texture, or blank if not defined
         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));
+                texture->SetResolveDirty(false);
+            }
+        }
     }
     }
 
 
     if (texture != textures_[index])
     if (texture != textures_[index])
@@ -1517,16 +1560,19 @@ void Graphics::SetRenderTarget(unsigned index, RenderSurface* renderTarget)
         }
         }
     }
     }
 
 
-    // If the rendertarget is also bound as a texture, replace with backup texture or null
     if (renderTarget)
     if (renderTarget)
     {
     {
         Texture* parentTexture = renderTarget->GetParentTexture();
         Texture* parentTexture = renderTarget->GetParentTexture();
 
 
+        // If the rendertarget is also bound as a texture, replace with backup texture or null
         for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
         for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
         {
         {
             if (textures_[i] == parentTexture)
             if (textures_[i] == parentTexture)
                 SetTexture(i, textures_[i]->GetBackupTexture());
                 SetTexture(i, textures_[i]->GetBackupTexture());
         }
         }
+
+        // If multisampled, mark the texture needing resolve
+        parentTexture->SetResolveDirty(true);
     }
     }
 
 
     // First rendertarget controls sRGB write mode
     // First rendertarget controls sRGB write mode
@@ -1895,10 +1941,9 @@ PODVector<int> Graphics::GetMultiSampleLevels() const
     SDL_GetDesktopDisplayMode(0, &mode);
     SDL_GetDesktopDisplayMode(0, &mode);
     D3DFORMAT fullscreenFormat = SDL_BITSPERPIXEL(mode.format) == 16 ? D3DFMT_R5G6B5 : D3DFMT_X8R8G8B8;
     D3DFORMAT fullscreenFormat = SDL_BITSPERPIXEL(mode.format) == 16 ? D3DFMT_R5G6B5 : D3DFMT_X8R8G8B8;
 
 
-    for (unsigned i = (int)D3DMULTISAMPLE_2_SAMPLES; i < (int)D3DMULTISAMPLE_16_SAMPLES; ++i)
+    for (int i = (int)D3DMULTISAMPLE_2_SAMPLES; i < (int)D3DMULTISAMPLE_16_SAMPLES; ++i)
     {
     {
-        if (SUCCEEDED(impl_->interface_->CheckDeviceMultiSampleType(impl_->adapter_, impl_->deviceType_, fullscreenFormat, FALSE,
-            (D3DMULTISAMPLE_TYPE)i, NULL)))
+        if (impl_->CheckMultiSampleSupport(fullscreenFormat, i))
             ret.Push(i);
             ret.Push(i);
     }
     }
 
 

+ 6 - 0
Source/Urho3D/Graphics/Direct3D9/D3D9GraphicsImpl.cpp

@@ -51,4 +51,10 @@ bool GraphicsImpl::CheckFormatSupport(D3DFORMAT format, DWORD usage, D3DRESOURCE
         false;
         false;
 }
 }
 
 
+bool GraphicsImpl::CheckMultiSampleSupport(D3DFORMAT format, int level)
+{
+    return interface_ ? SUCCEEDED(interface_->CheckDeviceMultiSampleType(adapter_, deviceType_, format, FALSE,
+        (D3DMULTISAMPLE_TYPE)level, NULL)) : false;
+}
+
 }
 }

+ 3 - 0
Source/Urho3D/Graphics/Direct3D9/D3D9GraphicsImpl.h

@@ -59,6 +59,9 @@ public:
     /// Return whether a texture format and usage is supported.
     /// Return whether a texture format and usage is supported.
     bool CheckFormatSupport(D3DFORMAT format, DWORD usage, D3DRESOURCETYPE type);
     bool CheckFormatSupport(D3DFORMAT format, DWORD usage, D3DRESOURCETYPE type);
 
 
+    /// Return whether a multisample level is supported.
+    bool CheckMultiSampleSupport(D3DFORMAT format, int level);
+
 private:
 private:
     /// Direct3D interface.
     /// Direct3D interface.
     IDirect3D9* interface_;
     IDirect3D9* interface_;

+ 36 - 3
Source/Urho3D/Graphics/Direct3D9/D3D9Texture2D.cpp

@@ -500,15 +500,28 @@ bool Texture2D::Create()
         break;
         break;
     }
     }
 
 
+    // Fall back to non-multisampled if unsupported multisampling mode
+    if (multiSample_ > 1)
+    {
+        GraphicsImpl* impl = graphics_->GetImpl();
+        if (!impl->CheckMultiSampleSupport((D3DFORMAT)format_,  multiSample_))
+        {
+            multiSample_ = 1;
+            autoResolve_ = false;
+        }
+    }
+
     IDirect3DDevice9* device = graphics_->GetImpl()->GetDevice();
     IDirect3DDevice9* device = graphics_->GetImpl()->GetDevice();
     // If creating a depth-stencil texture, and it is not supported, create a depth-stencil surface instead
     // If creating a depth-stencil texture, and it is not supported, create a depth-stencil surface instead
-    if (usage_ == TEXTURE_DEPTHSTENCIL && !graphics_->GetImpl()->CheckFormatSupport((D3DFORMAT)format_, d3dUsage, D3DRTYPE_TEXTURE))
+    // Multisampled surfaces need also to be created this way
+    if (usage_ == TEXTURE_DEPTHSTENCIL && (multiSample_ > 1 || !graphics_->GetImpl()->CheckFormatSupport((D3DFORMAT)format_, 
+        d3dUsage, D3DRTYPE_TEXTURE)))
     {
     {
         HRESULT hr = device->CreateDepthStencilSurface(
         HRESULT hr = device->CreateDepthStencilSurface(
             (UINT)width_,
             (UINT)width_,
             (UINT)height_,
             (UINT)height_,
             (D3DFORMAT)format_,
             (D3DFORMAT)format_,
-            D3DMULTISAMPLE_NONE,
+            (multiSample_ > 1) ? (D3DMULTISAMPLE_TYPE)multiSample_ : D3DMULTISAMPLE_NONE,
             0,
             0,
             FALSE,
             FALSE,
             (IDirect3DSurface9**)&renderSurface_->surface_,
             (IDirect3DSurface9**)&renderSurface_->surface_,
@@ -542,8 +555,28 @@ bool Texture2D::Create()
 
 
         levels_ = ((IDirect3DTexture9*)object_.ptr_)->GetLevelCount();
         levels_ = ((IDirect3DTexture9*)object_.ptr_)->GetLevelCount();
 
 
-        if (usage_ >= TEXTURE_RENDERTARGET)
+        // Create the multisampled rendertarget for rendering to if necessary
+        if (usage_ == TEXTURE_RENDERTARGET && multiSample_ > 1)
+        {
+            HRESULT hr = device->CreateRenderTarget(
+                (UINT)width_,
+                (UINT)height_,
+                (D3DFORMAT)format_,
+                (multiSample_ > 1) ? (D3DMULTISAMPLE_TYPE)multiSample_ : D3DMULTISAMPLE_NONE,
+                0,
+                FALSE,
+                (IDirect3DSurface9**)&renderSurface_->surface_,
+                0);
+            if (FAILED(hr))
+            {
+                URHO3D_SAFE_RELEASE(renderSurface_->surface_);
+                URHO3D_LOGD3DERROR("Could not create multisampled rendertarget surface", hr);
+                return false;
+            }
+        }
+        else if (usage_ >= TEXTURE_RENDERTARGET)
         {
         {
+            // Else use the texture surface directly for rendering
             hr = ((IDirect3DTexture9*)object_.ptr_)->GetSurfaceLevel(0, (IDirect3DSurface9**)&renderSurface_->surface_);
             hr = ((IDirect3DTexture9*)object_.ptr_)->GetSurfaceLevel(0, (IDirect3DSurface9**)&renderSurface_->surface_);
             if (FAILED(hr))
             if (FAILED(hr))
                 URHO3D_LOGD3DERROR("Could not get rendertarget surface", hr);
                 URHO3D_LOGD3DERROR("Could not get rendertarget surface", hr);

+ 2 - 0
Source/Urho3D/Graphics/Graphics.h

@@ -128,6 +128,8 @@ public:
     void Clear(unsigned flags, const Color& color = Color(0.0f, 0.0f, 0.0f, 0.0f), float depth = 1.0f, unsigned stencil = 0);
     void Clear(unsigned flags, const Color& color = Color(0.0f, 0.0f, 0.0f, 0.0f), float depth = 1.0f, unsigned stencil = 0);
     /// Resolve multisampled backbuffer to a texture rendertarget. The texture's size should match the viewport size.
     /// Resolve multisampled backbuffer to a texture rendertarget. The texture's size should match the viewport size.
     bool ResolveToTexture(Texture2D* destination, const IntRect& viewport);
     bool ResolveToTexture(Texture2D* destination, const IntRect& viewport);
+    /// Resolve a multisampled texture on itself.
+    bool ResolveToTexture(Texture2D* texture);
     /// Draw non-indexed geometry.
     /// Draw non-indexed geometry.
     void Draw(PrimitiveType type, unsigned vertexStart, unsigned vertexCount);
     void Draw(PrimitiveType type, unsigned vertexStart, unsigned vertexCount);
     /// Draw indexed geometry.
     /// Draw indexed geometry.

+ 10 - 0
Source/Urho3D/Graphics/RenderSurface.cpp

@@ -94,6 +94,16 @@ TextureUsage RenderSurface::GetUsage() const
     return parentTexture_->GetUsage();
     return parentTexture_->GetUsage();
 }
 }
 
 
+int RenderSurface::GetMultiSample() const
+{
+    return parentTexture_->GetMultiSample();
+}
+
+bool RenderSurface::GetAutoResolve() const
+{
+    return parentTexture_->GetAutoResolve();
+}
+
 Viewport* RenderSurface::GetViewport(unsigned index) const
 Viewport* RenderSurface::GetViewport(unsigned index) const
 {
 {
     return index < viewports_.Size() ? viewports_[index] : (Viewport*)0;
     return index < viewports_.Size() ? viewports_[index] : (Viewport*)0;

+ 6 - 0
Source/Urho3D/Graphics/RenderSurface.h

@@ -71,6 +71,12 @@ public:
     /// Return usage.
     /// Return usage.
     TextureUsage GetUsage() const;
     TextureUsage GetUsage() const;
 
 
+    /// Return multisampling level.
+    int GetMultiSample() const;
+
+    /// Return multisampling autoresolve mode.
+    bool GetAutoResolve() const;
+
     /// Return number of viewports.
     /// Return number of viewports.
     unsigned GetNumViewports() const { return viewports_.Size(); }
     unsigned GetNumViewports() const { return viewports_.Size(); }
 
 

+ 16 - 8
Source/Urho3D/Graphics/Renderer.cpp

@@ -1005,7 +1005,7 @@ Texture2D* Renderer::GetShadowMap(Light* light, Camera* camera, unsigned viewWid
     return newShadowMap;
     return newShadowMap;
 }
 }
 
 
-Texture* Renderer::GetScreenBuffer(int width, int height, unsigned format, bool cubemap, bool filtered, bool srgb,
+Texture* Renderer::GetScreenBuffer(int width, int height, unsigned format, int multiSample, bool autoResolve, bool cubemap, bool filtered, bool srgb,
     unsigned persistentKey)
     unsigned persistentKey)
 {
 {
     bool depthStencil = (format == Graphics::GetDepthStencilFormat()) || (format == Graphics::GetReadableDepthFormat());
     bool depthStencil = (format == Graphics::GetDepthStencilFormat()) || (format == Graphics::GetReadableDepthFormat());
@@ -1018,13 +1018,19 @@ Texture* Renderer::GetScreenBuffer(int width, int height, unsigned format, bool
     if (cubemap)
     if (cubemap)
         height = width;
         height = width;
 
 
-    long long searchKey = ((long long)format << 32) | (width << 16) | height;
+    multiSample = Clamp(multiSample, 1, 16);
+    if (multiSample == 1)
+        autoResolve = false;
+
+    long long searchKey = ((long long)format << 32) | (multiSample << 24) | (width << 12) | height;
     if (filtered)
     if (filtered)
         searchKey |= 0x8000000000000000LL;
         searchKey |= 0x8000000000000000LL;
     if (srgb)
     if (srgb)
         searchKey |= 0x4000000000000000LL;
         searchKey |= 0x4000000000000000LL;
     if (cubemap)
     if (cubemap)
         searchKey |= 0x2000000000000000LL;
         searchKey |= 0x2000000000000000LL;
+    if (autoResolve)
+        searchKey |= 0x1000000000000000LL;
 
 
     // Add persistent key if defined
     // Add persistent key if defined
     if (persistentKey)
     if (persistentKey)
@@ -1046,7 +1052,7 @@ Texture* Renderer::GetScreenBuffer(int width, int height, unsigned format, bool
         if (!cubemap)
         if (!cubemap)
         {
         {
             SharedPtr<Texture2D> newTex2D(new Texture2D(context_));
             SharedPtr<Texture2D> newTex2D(new Texture2D(context_));
-            newTex2D->SetSize(width, height, format, depthStencil ? TEXTURE_DEPTHSTENCIL : TEXTURE_RENDERTARGET);
+            newTex2D->SetSize(width, height, format, depthStencil ? TEXTURE_DEPTHSTENCIL : TEXTURE_RENDERTARGET, multiSample, autoResolve);
 
 
 #ifdef URHO3D_OPENGL
 #ifdef URHO3D_OPENGL
             // OpenGL hack: clear persistent floating point screen buffers to ensure the initial contents aren't illegal (NaN)?
             // OpenGL hack: clear persistent floating point screen buffers to ensure the initial contents aren't illegal (NaN)?
@@ -1088,7 +1094,7 @@ Texture* Renderer::GetScreenBuffer(int width, int height, unsigned format, bool
     }
     }
 }
 }
 
 
-RenderSurface* Renderer::GetDepthStencil(int width, int height)
+RenderSurface* Renderer::GetDepthStencil(int width, int height, int multiSample, bool autoResolve)
 {
 {
     // Return the default depth-stencil surface if applicable
     // Return the default depth-stencil surface if applicable
     // (when using OpenGL Graphics will allocate right size surfaces on demand to emulate Direct3D9)
     // (when using OpenGL Graphics will allocate right size surfaces on demand to emulate Direct3D9)
@@ -1096,8 +1102,8 @@ RenderSurface* Renderer::GetDepthStencil(int width, int height)
         return 0;
         return 0;
     else
     else
     {
     {
-        return static_cast<Texture2D*>(GetScreenBuffer(width, height, Graphics::GetDepthStencilFormat(), false, false,
-            false))->GetRenderSurface();
+        return static_cast<Texture2D*>(GetScreenBuffer(width, height, Graphics::GetDepthStencilFormat(), multiSample, autoResolve,
+            false, false, false))->GetRenderSurface();
     }
     }
 }
 }
 
 
@@ -1962,9 +1968,11 @@ void Renderer::BlurShadowMap(View* view, Texture2D* shadowMap, float blurScale)
     graphics_->SetScissorTest(false);
     graphics_->SetScissorTest(false);
 
 
     // Get a temporary render buffer
     // Get a temporary render buffer
-    Texture2D* tmpBuffer = static_cast<Texture2D*>(GetScreenBuffer(shadowMap->GetWidth(), shadowMap->GetHeight(), shadowMap->GetFormat(), false, false, false));
+    Texture2D* tmpBuffer = static_cast<Texture2D*>(GetScreenBuffer(shadowMap->GetWidth(), shadowMap->GetHeight(),
+        shadowMap->GetFormat(), 1, false, false, false, false));
     graphics_->SetRenderTarget(0, tmpBuffer->GetRenderSurface());
     graphics_->SetRenderTarget(0, tmpBuffer->GetRenderSurface());
-    graphics_->SetDepthStencil(GetDepthStencil(shadowMap->GetWidth(), shadowMap->GetHeight()));
+    graphics_->SetDepthStencil(GetDepthStencil(shadowMap->GetWidth(), shadowMap->GetHeight(), shadowMap->GetMultiSample(),
+        shadowMap->GetAutoResolve()));
     graphics_->SetViewport(IntRect(0, 0, shadowMap->GetWidth(), shadowMap->GetHeight()));
     graphics_->SetViewport(IntRect(0, 0, shadowMap->GetWidth(), shadowMap->GetHeight()));
 
 
     // Get shaders
     // Get shaders

+ 2 - 2
Source/Urho3D/Graphics/Renderer.h

@@ -389,9 +389,9 @@ public:
     Texture2D* GetShadowMap(Light* light, Camera* camera, unsigned viewWidth, unsigned viewHeight);
     Texture2D* GetShadowMap(Light* light, Camera* camera, unsigned viewWidth, unsigned viewHeight);
     /// Allocate a rendertarget or depth-stencil texture for deferred rendering or postprocessing. Should only be called during actual rendering, not before.
     /// Allocate a rendertarget or depth-stencil texture for deferred rendering or postprocessing. Should only be called during actual rendering, not before.
     Texture* GetScreenBuffer
     Texture* GetScreenBuffer
-        (int width, int height, unsigned format, bool cubemap, bool filtered, bool srgb, unsigned persistentKey = 0);
+        (int width, int height, unsigned format, int multiSample, bool autoResolve, bool cubemap, bool filtered, bool srgb, unsigned persistentKey = 0);
     /// Allocate a depth-stencil surface that does not need to be readable. Should only be called during actual rendering, not before.
     /// Allocate a depth-stencil surface that does not need to be readable. Should only be called during actual rendering, not before.
-    RenderSurface* GetDepthStencil(int width, int height);
+    RenderSurface* GetDepthStencil(int width, int height, int multiSample, bool autoResolve);
     /// Allocate an occlusion buffer.
     /// Allocate an occlusion buffer.
     OcclusionBuffer* GetOcclusionBuffer(Camera* camera);
     OcclusionBuffer* GetOcclusionBuffer(Camera* camera);
     /// Allocate a temporary shadow camera and a scene node for it. Is thread-safe.
     /// Allocate a temporary shadow camera and a scene node for it. Is thread-safe.

+ 4 - 1
Source/Urho3D/Graphics/Texture.cpp

@@ -69,8 +69,11 @@ Texture::Texture(Context* context) :
     shadowCompare_(false),
     shadowCompare_(false),
     filterMode_(FILTER_DEFAULT),
     filterMode_(FILTER_DEFAULT),
     anisotropy_(0),
     anisotropy_(0),
+    multiSample_(1),
     sRGB_(false),
     sRGB_(false),
-    parametersDirty_(true)
+    parametersDirty_(true),
+    autoResolve_(false),
+    resolveDirty_(false)
 {
 {
     for (int i = 0; i < MAX_COORDS; ++i)
     for (int i = 0; i < MAX_COORDS; ++i)
         addressMode_[i] = ADDRESS_WRAP;
         addressMode_[i] = ADDRESS_WRAP;

+ 18 - 0
Source/Urho3D/Graphics/Texture.h

@@ -102,6 +102,15 @@ public:
     /// Return backup texture.
     /// Return backup texture.
     Texture* GetBackupTexture() const { return backupTexture_; }
     Texture* GetBackupTexture() const { return backupTexture_; }
 
 
+    /// Return texture multisampling level (1 = no multisampling).
+    int GetMultiSample() const { return multiSample_; }
+
+    /// Return texture multisampling autoresolve mode. When true, the texture is resolved before being sampled on SetTexture(). When false, the texture will not be resolved and must be read as individual samples in the shader.
+    bool GetAutoResolve() const { return autoResolve_; }
+
+    /// Return whether multisampled texture needs resolve.
+    bool IsResolveDirty() const { return resolveDirty_; }
+
     /// Return mip levels to skip on a quality setting when loading.
     /// Return mip levels to skip on a quality setting when loading.
     int GetMipsToSkip(int quality) const;
     int GetMipsToSkip(int quality) const;
     /// Return mip level width, or 0 if level does not exist.
     /// Return mip level width, or 0 if level does not exist.
@@ -147,6 +156,9 @@ public:
     /// Convert format to sRGB. Not used on Direct3D9.
     /// Convert format to sRGB. Not used on Direct3D9.
     unsigned GetSRGBFormat(unsigned format);
     unsigned GetSRGBFormat(unsigned format);
 
 
+    /// Set or clear the need resolve flag. Called internally by Graphics.
+    void SetResolveDirty(bool enable) { resolveDirty_ = enable; }
+
     /// Check maximum allowed mip levels for a specific texture size.
     /// Check maximum allowed mip levels for a specific texture size.
     static unsigned CheckMaxLevels(int width, int height, unsigned requestedLevels);
     static unsigned CheckMaxLevels(int width, int height, unsigned requestedLevels);
     /// Check maximum allowed mip levels for a specific 3D texture size.
     /// Check maximum allowed mip levels for a specific 3D texture size.
@@ -203,10 +215,16 @@ protected:
     unsigned mipsToSkip_[MAX_TEXTURE_QUALITY_LEVELS];
     unsigned mipsToSkip_[MAX_TEXTURE_QUALITY_LEVELS];
     /// Border color.
     /// Border color.
     Color borderColor_;
     Color borderColor_;
+    /// Multisampling level.
+    int multiSample_;
     /// sRGB sampling and writing mode flag.
     /// sRGB sampling and writing mode flag.
     bool sRGB_;
     bool sRGB_;
     /// Parameters dirty flag.
     /// Parameters dirty flag.
     bool parametersDirty_;
     bool parametersDirty_;
+    /// Multisampling autoresolve flag.
+    bool autoResolve_;
+    /// Multisampling resolve needed -flag.
+    bool resolveDirty_;
     /// Backup texture.
     /// Backup texture.
     SharedPtr<Texture> backupTexture_;
     SharedPtr<Texture> backupTexture_;
 };
 };

+ 12 - 1
Source/Urho3D/Graphics/Texture2D.cpp

@@ -109,7 +109,7 @@ bool Texture2D::EndLoad()
     return success;
     return success;
 }
 }
 
 
-bool Texture2D::SetSize(int width, int height, unsigned format, TextureUsage usage)
+bool Texture2D::SetSize(int width, int height, unsigned format, TextureUsage usage, int multiSample, bool autoResolve)
 {
 {
     if (width <= 0 || height <= 0)
     if (width <= 0 || height <= 0)
     {
     {
@@ -117,6 +117,15 @@ bool Texture2D::SetSize(int width, int height, unsigned format, TextureUsage usa
         return false;
         return false;
     }
     }
 
 
+    multiSample = Clamp(multiSample, 1, 16);
+    if (multiSample == 1)
+        autoResolve = false;
+    else if (multiSample > 1 && usage < TEXTURE_RENDERTARGET)
+    {
+        URHO3D_LOGERROR("Multisampling is only supported for rendertarget or depth-stencil textures");
+        return false;
+    }
+
     // Delete the old rendersurface if any
     // Delete the old rendersurface if any
     renderSurface_.Reset();
     renderSurface_.Reset();
 
 
@@ -141,6 +150,8 @@ bool Texture2D::SetSize(int width, int height, unsigned format, TextureUsage usa
     width_ = width;
     width_ = width;
     height_ = height;
     height_ = height;
     format_ = format;
     format_ = format;
+    multiSample_ = multiSample;
+    autoResolve_ = autoResolve;
 
 
     return Create();
     return Create();
 }
 }

+ 2 - 2
Source/Urho3D/Graphics/Texture2D.h

@@ -56,8 +56,8 @@ public:
     /// Release the texture.
     /// Release the texture.
     virtual void Release();
     virtual void Release();
 
 
-    /// Set size, format and usage. Zero size will follow application window size. Return true if successful.
-    bool SetSize(int width, int height, unsigned format, TextureUsage usage = TEXTURE_STATIC);
+    /// Set size, format, usage and multisampling parameters for rendertargets. Zero size will follow application window size. Return true if successful. Autoresolve false means that texture will be read as individual samples in the shader and is not supported on Direct3D9.
+    bool SetSize(int width, int height, unsigned format, TextureUsage usage = TEXTURE_STATIC, int multiSample = 1, bool autoResolve = true);
     /// Set data either partially or fully on a mip level. Return true if successful.
     /// Set data either partially or fully on a mip level. Return true if successful.
     bool SetData(unsigned level, int x, int y, int width, int height, const void* data);
     bool SetData(unsigned level, int x, int y, int width, int height, const void* data);
     /// Set data from an image. Return true if successful. Optionally make a single channel image alpha-only.
     /// Set data from an image. Return true if successful. Optionally make a single channel image alpha-only.

+ 11 - 7
Source/Urho3D/Graphics/View.cpp

@@ -1707,7 +1707,7 @@ void View::SetRenderTargets(RenderPathCommand& command)
                 if (!depthOnlyDummyTexture_)
                 if (!depthOnlyDummyTexture_)
                 {
                 {
                     depthOnlyDummyTexture_ = renderer_->GetScreenBuffer(texture->GetWidth(), texture->GetHeight(),
                     depthOnlyDummyTexture_ = renderer_->GetScreenBuffer(texture->GetWidth(), texture->GetHeight(),
-                        graphics_->GetDummyColorFormat(), false, false, false);
+                        graphics_->GetDummyColorFormat(), texture->GetMultiSample(), texture->GetAutoResolve(), false, false, false);
                 }
                 }
 #endif
 #endif
                 graphics_->SetRenderTarget(0, GetRenderSurfaceFromTexture(depthOnlyDummyTexture_));
                 graphics_->SetRenderTarget(0, GetRenderSurfaceFromTexture(depthOnlyDummyTexture_));
@@ -2005,13 +2005,15 @@ void View::AllocateScreenBuffers()
     // Allocate screen buffers with filtering active in case the quad commands need that
     // Allocate screen buffers with filtering active in case the quad commands need that
     // Follow the sRGB mode of the destination render target
     // Follow the sRGB mode of the destination render target
     bool sRGB = renderTarget_ ? renderTarget_->GetParentTexture()->GetSRGB() : graphics_->GetSRGB();
     bool sRGB = renderTarget_ ? renderTarget_->GetParentTexture()->GetSRGB() : graphics_->GetSRGB();
+    int multiSample = renderTarget_ ? renderTarget_->GetMultiSample() : 1;
+    bool autoResolve = renderTarget_ ? renderTarget_->GetAutoResolve() : false;
     substituteRenderTarget_ = needSubstitute ? GetRenderSurfaceFromTexture(renderer_->GetScreenBuffer(viewSize_.x_, viewSize_.y_,
     substituteRenderTarget_ = needSubstitute ? GetRenderSurfaceFromTexture(renderer_->GetScreenBuffer(viewSize_.x_, viewSize_.y_,
-        format, false, true, sRGB)) : (RenderSurface*)0;
+        format, multiSample, autoResolve, false, true, sRGB)) : (RenderSurface*)0;
     for (unsigned i = 0; i < MAX_VIEWPORT_TEXTURES; ++i)
     for (unsigned i = 0; i < MAX_VIEWPORT_TEXTURES; ++i)
     {
     {
         viewportTextures_[i] =
         viewportTextures_[i] =
-            i < numViewportTextures ? renderer_->GetScreenBuffer(viewSize_.x_, viewSize_.y_, format, false, true, sRGB) :
-                (Texture*)0;
+            i < numViewportTextures ? renderer_->GetScreenBuffer(viewSize_.x_, viewSize_.y_, format, multiSample, autoResolve,
+                false, true, sRGB) : (Texture*)0;
     }
     }
     // If using a substitute render target and pingponging, the substitute can act as the second viewport texture
     // If using a substitute render target and pingponging, the substitute can act as the second viewport texture
     if (numViewportTextures == 1 && substituteRenderTarget_)
     if (numViewportTextures == 1 && substituteRenderTarget_)
@@ -2043,7 +2045,7 @@ void View::AllocateScreenBuffers()
 
 
         // If the rendertarget is persistent, key it with a hash derived from the RT name and the view's pointer
         // If the rendertarget is persistent, key it with a hash derived from the RT name and the view's pointer
         renderTargets_[rtInfo.name_] =
         renderTargets_[rtInfo.name_] =
-            renderer_->GetScreenBuffer(intWidth, intHeight, rtInfo.format_, rtInfo.cubemap_, rtInfo.filtered_, rtInfo.sRGB_,
+            renderer_->GetScreenBuffer(intWidth, intHeight, rtInfo.format_, 1, false, rtInfo.cubemap_, rtInfo.filtered_, rtInfo.sRGB_,
                 rtInfo.persistent_ ? StringHash(rtInfo.name_).Value() + (unsigned)(size_t)this : 0);
                 rtInfo.persistent_ ? StringHash(rtInfo.name_).Value() + (unsigned)(size_t)this : 0);
     }
     }
 }
 }
@@ -3007,7 +3009,8 @@ void View::RenderShadowMap(const LightBatchQueue& queue)
         // Disable other render targets
         // Disable other render targets
         for (unsigned i = 1; i < MAX_RENDERTARGETS; ++i)
         for (unsigned i = 1; i < MAX_RENDERTARGETS; ++i)
             graphics_->SetRenderTarget(i, (RenderSurface*) 0);
             graphics_->SetRenderTarget(i, (RenderSurface*) 0);
-        graphics_->SetDepthStencil(renderer_->GetDepthStencil(shadowMap->GetWidth(), shadowMap->GetHeight()));
+        graphics_->SetDepthStencil(renderer_->GetDepthStencil(shadowMap->GetWidth(), shadowMap->GetHeight(),
+            shadowMap->GetMultiSample(), shadowMap->GetAutoResolve()));
         graphics_->SetViewport(IntRect(0, 0, shadowMap->GetWidth(), shadowMap->GetHeight()));
         graphics_->SetViewport(IntRect(0, 0, shadowMap->GetWidth(), shadowMap->GetHeight()));
         graphics_->Clear(CLEAR_DEPTH | CLEAR_COLOR, Color::WHITE);
         graphics_->Clear(CLEAR_DEPTH | CLEAR_COLOR, Color::WHITE);
 
 
@@ -3064,7 +3067,8 @@ RenderSurface* View::GetDepthStencil(RenderSurface* renderTarget)
     RenderSurface* depthStencil = renderTarget->GetLinkedDepthStencil();
     RenderSurface* depthStencil = renderTarget->GetLinkedDepthStencil();
     // Finally get one from Renderer
     // Finally get one from Renderer
     if (!depthStencil)
     if (!depthStencil)
-        depthStencil = renderer_->GetDepthStencil(renderTarget->GetWidth(), renderTarget->GetHeight());
+        depthStencil = renderer_->GetDepthStencil(renderTarget->GetWidth(), renderTarget->GetHeight(),
+            renderTarget->GetMultiSample(), renderTarget->GetAutoResolve());
     return depthStencil;
     return depthStencil;
 }
 }
 
 

+ 1 - 1
Source/Urho3D/LuaScript/pkgs/Graphics/Texture2D.pkg

@@ -7,7 +7,7 @@ class Texture2D : public Texture
     Texture2D();
     Texture2D();
     ~Texture2D();
     ~Texture2D();
 
 
-    bool SetSize(int width, int height, unsigned format, TextureUsage usage = TEXTURE_STATIC);
+    bool SetSize(int width, int height, unsigned format, TextureUsage usage = TEXTURE_STATIC, int multiSample = 1, bool autoResolve = true);
     bool SetData(Image* image, bool useAlpha = false);
     bool SetData(Image* image, bool useAlpha = false);
 
 
     RenderSurface* GetRenderSurface() const;
     RenderSurface* GetRenderSurface() const;