1//
2// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// RenderTarget11.cpp: Implements a DX11-specific wrapper for ID3D11View pointers
8// retained by Renderbuffers.
9
10#include "libGLESv2/renderer/d3d/d3d11/RenderTarget11.h"
11#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h"
12#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h"
13#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h"
14#include "libGLESv2/main.h"
15
16namespace rx
17{
18
19static bool getTextureProperties(ID3D11Resource *resource, unsigned int *mipLevels, unsigned int *samples)
20{
21    ID3D11Texture1D *texture1D = d3d11::DynamicCastComObject<ID3D11Texture1D>(resource);
22    if (texture1D)
23    {
24        D3D11_TEXTURE1D_DESC texDesc;
25        texture1D->GetDesc(&texDesc);
26        SafeRelease(texture1D);
27
28        *mipLevels = texDesc.MipLevels;
29        *samples = 0;
30
31        return true;
32    }
33
34    ID3D11Texture2D *texture2D = d3d11::DynamicCastComObject<ID3D11Texture2D>(resource);
35    if (texture2D)
36    {
37        D3D11_TEXTURE2D_DESC texDesc;
38        texture2D->GetDesc(&texDesc);
39        SafeRelease(texture2D);
40
41        *mipLevels = texDesc.MipLevels;
42        *samples = texDesc.SampleDesc.Count > 1 ? texDesc.SampleDesc.Count : 0;
43
44        return true;
45    }
46
47    ID3D11Texture3D *texture3D = d3d11::DynamicCastComObject<ID3D11Texture3D>(resource);
48    if (texture3D)
49    {
50        D3D11_TEXTURE3D_DESC texDesc;
51        texture3D->GetDesc(&texDesc);
52        SafeRelease(texture3D);
53
54        *mipLevels = texDesc.MipLevels;
55        *samples = 0;
56
57        return true;
58    }
59
60    return false;
61}
62
63static unsigned int getRTVSubresourceIndex(ID3D11Resource *resource, ID3D11RenderTargetView *view)
64{
65    D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
66    view->GetDesc(&rtvDesc);
67
68    unsigned int mipSlice = 0;
69    unsigned int arraySlice = 0;
70
71    switch (rtvDesc.ViewDimension)
72    {
73      case D3D11_RTV_DIMENSION_TEXTURE1D:
74        mipSlice = rtvDesc.Texture1D.MipSlice;
75        arraySlice = 0;
76        break;
77
78      case D3D11_RTV_DIMENSION_TEXTURE1DARRAY:
79        mipSlice = rtvDesc.Texture1DArray.MipSlice;
80        arraySlice = rtvDesc.Texture1DArray.FirstArraySlice;
81        break;
82
83      case D3D11_RTV_DIMENSION_TEXTURE2D:
84        mipSlice = rtvDesc.Texture2D.MipSlice;
85        arraySlice = 0;
86        break;
87
88      case D3D11_RTV_DIMENSION_TEXTURE2DARRAY:
89        mipSlice = rtvDesc.Texture2DArray.MipSlice;
90        arraySlice = rtvDesc.Texture2DArray.FirstArraySlice;
91        break;
92
93      case D3D11_RTV_DIMENSION_TEXTURE2DMS:
94        mipSlice = 0;
95        arraySlice = 0;
96        break;
97
98      case D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY:
99        mipSlice = 0;
100        arraySlice = rtvDesc.Texture2DMSArray.FirstArraySlice;
101        break;
102
103      case D3D11_RTV_DIMENSION_TEXTURE3D:
104        mipSlice = rtvDesc.Texture3D.MipSlice;
105        arraySlice = 0;
106        break;
107
108      case D3D11_RTV_DIMENSION_UNKNOWN:
109      case D3D11_RTV_DIMENSION_BUFFER:
110        UNIMPLEMENTED();
111        break;
112
113      default:
114        UNREACHABLE();
115        break;
116    }
117
118    unsigned int mipLevels, samples;
119    getTextureProperties(resource,  &mipLevels, &samples);
120
121    return D3D11CalcSubresource(mipSlice, arraySlice, mipLevels);
122}
123
124static unsigned int getDSVSubresourceIndex(ID3D11Resource *resource, ID3D11DepthStencilView *view)
125{
126    D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc;
127    view->GetDesc(&dsvDesc);
128
129    unsigned int mipSlice = 0;
130    unsigned int arraySlice = 0;
131
132    switch (dsvDesc.ViewDimension)
133    {
134      case D3D11_DSV_DIMENSION_TEXTURE1D:
135        mipSlice = dsvDesc.Texture1D.MipSlice;
136        arraySlice = 0;
137        break;
138
139      case D3D11_DSV_DIMENSION_TEXTURE1DARRAY:
140        mipSlice = dsvDesc.Texture1DArray.MipSlice;
141        arraySlice = dsvDesc.Texture1DArray.FirstArraySlice;
142        break;
143
144      case D3D11_DSV_DIMENSION_TEXTURE2D:
145        mipSlice = dsvDesc.Texture2D.MipSlice;
146        arraySlice = 0;
147        break;
148
149      case D3D11_DSV_DIMENSION_TEXTURE2DARRAY:
150        mipSlice = dsvDesc.Texture2DArray.MipSlice;
151        arraySlice = dsvDesc.Texture2DArray.FirstArraySlice;
152        break;
153
154      case D3D11_DSV_DIMENSION_TEXTURE2DMS:
155        mipSlice = 0;
156        arraySlice = 0;
157        break;
158
159      case D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY:
160        mipSlice = 0;
161        arraySlice = dsvDesc.Texture2DMSArray.FirstArraySlice;
162        break;
163
164      case D3D11_DSV_DIMENSION_UNKNOWN:
165        UNIMPLEMENTED();
166        break;
167
168      default:
169        UNREACHABLE();
170        break;
171    }
172
173    unsigned int mipLevels, samples;
174    getTextureProperties(resource, &mipLevels, &samples);
175
176    return D3D11CalcSubresource(mipSlice, arraySlice, mipLevels);
177}
178
179RenderTarget11::RenderTarget11(Renderer *renderer, ID3D11RenderTargetView *rtv, ID3D11Resource *resource,
180                               ID3D11ShaderResourceView *srv, GLsizei width, GLsizei height, GLsizei depth)
181{
182    mRenderer = Renderer11::makeRenderer11(renderer);
183
184    mTexture = resource;
185    if (mTexture)
186    {
187        mTexture->AddRef();
188    }
189
190    mRenderTarget = rtv;
191    if (mRenderTarget)
192    {
193        mRenderTarget->AddRef();
194    }
195
196    mDepthStencil = NULL;
197
198    mShaderResource = srv;
199    if (mShaderResource)
200    {
201        mShaderResource->AddRef();
202    }
203
204    mSubresourceIndex = 0;
205
206    if (mRenderTarget && mTexture)
207    {
208        D3D11_RENDER_TARGET_VIEW_DESC desc;
209        mRenderTarget->GetDesc(&desc);
210
211        unsigned int mipLevels, samples;
212        getTextureProperties(mTexture, &mipLevels, &samples);
213
214        mSubresourceIndex = getRTVSubresourceIndex(mTexture, mRenderTarget);
215        mWidth = width;
216        mHeight = height;
217        mDepth = depth;
218        mSamples = samples;
219
220        const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(desc.Format);
221        mInternalFormat = dxgiFormatInfo.internalFormat;
222        mActualFormat = dxgiFormatInfo.internalFormat;
223    }
224}
225
226RenderTarget11::RenderTarget11(Renderer *renderer, ID3D11DepthStencilView *dsv, ID3D11Resource *resource,
227                               ID3D11ShaderResourceView *srv, GLsizei width, GLsizei height, GLsizei depth)
228{
229    mRenderer = Renderer11::makeRenderer11(renderer);
230
231    mTexture = resource;
232    if (mTexture)
233    {
234        mTexture->AddRef();
235    }
236
237    mRenderTarget = NULL;
238
239    mDepthStencil = dsv;
240    if (mDepthStencil)
241    {
242        mDepthStencil->AddRef();
243    }
244
245    mShaderResource = srv;
246    if (mShaderResource)
247    {
248        mShaderResource->AddRef();
249    }
250
251    mSubresourceIndex = 0;
252
253    if (mDepthStencil && mTexture)
254    {
255        D3D11_DEPTH_STENCIL_VIEW_DESC desc;
256        mDepthStencil->GetDesc(&desc);
257
258        unsigned int mipLevels, samples;
259        getTextureProperties(mTexture, &mipLevels, &samples);
260
261        mSubresourceIndex = getDSVSubresourceIndex(mTexture, mDepthStencil);
262        mWidth = width;
263        mHeight = height;
264        mDepth = depth;
265        mSamples = samples;
266
267        const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(desc.Format);
268        mInternalFormat = dxgiFormatInfo.internalFormat;
269        mActualFormat = dxgiFormatInfo.internalFormat;
270    }
271}
272
273RenderTarget11::RenderTarget11(Renderer *renderer, GLsizei width, GLsizei height, GLenum internalFormat, GLsizei samples)
274{
275    mRenderer = Renderer11::makeRenderer11(renderer);
276    mTexture = NULL;
277    mRenderTarget = NULL;
278    mDepthStencil = NULL;
279    mShaderResource = NULL;
280
281    const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalFormat);
282    const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(formatInfo.texFormat);
283
284    const gl::TextureCaps &textureCaps = mRenderer->getRendererTextureCaps().get(internalFormat);
285    GLuint supportedSamples = textureCaps.getNearestSamples(samples);
286
287    if (width > 0 && height > 0)
288    {
289        // Create texture resource
290        D3D11_TEXTURE2D_DESC desc;
291        desc.Width = width;
292        desc.Height = height;
293        desc.MipLevels = 1;
294        desc.ArraySize = 1;
295        desc.Format = formatInfo.texFormat;
296        desc.SampleDesc.Count = (supportedSamples == 0) ? 1 : supportedSamples;
297        desc.SampleDesc.Quality = 0;
298        desc.Usage = D3D11_USAGE_DEFAULT;
299        desc.CPUAccessFlags = 0;
300        desc.MiscFlags = 0;
301
302        // If a rendertarget or depthstencil format exists for this texture format,
303        // we'll flag it to allow binding that way. Shader resource views are a little
304        // more complicated.
305        bool bindRTV = false, bindDSV = false, bindSRV = false;
306        bindRTV = (formatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN);
307        bindDSV = (formatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN);
308        if (formatInfo.srvFormat != DXGI_FORMAT_UNKNOWN)
309        {
310            // Multisample targets flagged for binding as depth stencil cannot also be
311            // flagged for binding as SRV, so make certain not to add the SRV flag for
312            // these targets.
313            bindSRV = !(formatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN && desc.SampleDesc.Count > 1);
314        }
315
316        desc.BindFlags = (bindRTV ? D3D11_BIND_RENDER_TARGET   : 0) |
317                         (bindDSV ? D3D11_BIND_DEPTH_STENCIL   : 0) |
318                         (bindSRV ? D3D11_BIND_SHADER_RESOURCE : 0);
319
320        ID3D11Device *device = mRenderer->getDevice();
321        ID3D11Texture2D *texture = NULL;
322        HRESULT result = device->CreateTexture2D(&desc, NULL, &texture);
323        mTexture = texture;
324
325        if (result == E_OUTOFMEMORY)
326        {
327            gl::error(GL_OUT_OF_MEMORY);
328            return;
329        }
330        ASSERT(SUCCEEDED(result));
331
332        if (bindSRV)
333        {
334            D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
335            srvDesc.Format = formatInfo.srvFormat;
336            srvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_SRV_DIMENSION_TEXTURE2D : D3D11_SRV_DIMENSION_TEXTURE2DMS;
337            srvDesc.Texture2D.MostDetailedMip = 0;
338            srvDesc.Texture2D.MipLevels = 1;
339            result = device->CreateShaderResourceView(mTexture, &srvDesc, &mShaderResource);
340
341            if (result == E_OUTOFMEMORY)
342            {
343                SafeRelease(mTexture);
344                gl::error(GL_OUT_OF_MEMORY);
345                return;
346            }
347            ASSERT(SUCCEEDED(result));
348        }
349
350        if (bindDSV)
351        {
352            D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc;
353            dsvDesc.Format = formatInfo.dsvFormat;
354            dsvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_DSV_DIMENSION_TEXTURE2D : D3D11_DSV_DIMENSION_TEXTURE2DMS;
355            dsvDesc.Texture2D.MipSlice = 0;
356            dsvDesc.Flags = 0;
357            result = device->CreateDepthStencilView(mTexture, &dsvDesc, &mDepthStencil);
358
359            if (result == E_OUTOFMEMORY)
360            {
361                SafeRelease(mTexture);
362                SafeRelease(mShaderResource);
363                gl::error(GL_OUT_OF_MEMORY);
364                return;
365            }
366            ASSERT(SUCCEEDED(result));
367        }
368
369        if (bindRTV)
370        {
371            D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
372            rtvDesc.Format = formatInfo.rtvFormat;
373            rtvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_RTV_DIMENSION_TEXTURE2D : D3D11_RTV_DIMENSION_TEXTURE2DMS;
374            rtvDesc.Texture2D.MipSlice = 0;
375            result = device->CreateRenderTargetView(mTexture, &rtvDesc, &mRenderTarget);
376
377            if (result == E_OUTOFMEMORY)
378            {
379                SafeRelease(mTexture);
380                SafeRelease(mShaderResource);
381                SafeRelease(mDepthStencil);
382                gl::error(GL_OUT_OF_MEMORY);
383                return;
384            }
385            ASSERT(SUCCEEDED(result));
386
387            if (formatInfo.dataInitializerFunction != NULL)
388            {
389                ID3D11DeviceContext *context = mRenderer->getDeviceContext();
390
391                const float clearValues[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
392                context->ClearRenderTargetView(mRenderTarget, clearValues);
393            }
394        }
395    }
396
397
398    mWidth = width;
399    mHeight = height;
400    mDepth = 1;
401    mInternalFormat = internalFormat;
402    mSamples = supportedSamples;
403    mActualFormat = dxgiFormatInfo.internalFormat;
404    mSubresourceIndex = D3D11CalcSubresource(0, 0, 1);
405}
406
407RenderTarget11::~RenderTarget11()
408{
409    SafeRelease(mTexture);
410    SafeRelease(mRenderTarget);
411    SafeRelease(mDepthStencil);
412    SafeRelease(mShaderResource);
413}
414
415RenderTarget11 *RenderTarget11::makeRenderTarget11(RenderTarget *target)
416{
417    ASSERT(HAS_DYNAMIC_TYPE(rx::RenderTarget11*, target));
418    return static_cast<rx::RenderTarget11*>(target);
419}
420
421void RenderTarget11::invalidate(GLint x, GLint y, GLsizei width, GLsizei height)
422{
423    // Currently a no-op
424}
425
426ID3D11Resource *RenderTarget11::getTexture() const
427{
428    return mTexture;
429}
430
431ID3D11RenderTargetView *RenderTarget11::getRenderTargetView() const
432{
433    return mRenderTarget;
434}
435
436ID3D11DepthStencilView *RenderTarget11::getDepthStencilView() const
437{
438    return mDepthStencil;
439}
440
441ID3D11ShaderResourceView *RenderTarget11::getShaderResourceView() const
442{
443    return mShaderResource;
444}
445
446unsigned int RenderTarget11::getSubresourceIndex() const
447{
448    return mSubresourceIndex;
449}
450
451}
452