Home | History | Annotate | Download | only in d3d11
      1 #include "precompiled.h"
      2 //
      3 // Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
      4 // Use of this source code is governed by a BSD-style license that can be
      5 // found in the LICENSE file.
      6 //
      7 
      8 // Image11.h: Implements the rx::Image11 class, which acts as the interface to
      9 // the actual underlying resources of a Texture
     10 
     11 #include "libGLESv2/renderer/d3d11/Renderer11.h"
     12 #include "libGLESv2/renderer/d3d11/Image11.h"
     13 #include "libGLESv2/renderer/d3d11/TextureStorage11.h"
     14 #include "libGLESv2/Framebuffer.h"
     15 #include "libGLESv2/Renderbuffer.h"
     16 
     17 #include "libGLESv2/main.h"
     18 #include "common/utilities.h"
     19 #include "libGLESv2/renderer/d3d11/formatutils11.h"
     20 #include "libGLESv2/renderer/d3d11/renderer11_utils.h"
     21 
     22 namespace rx
     23 {
     24 
     25 Image11::Image11()
     26 {
     27     mStagingTexture = NULL;
     28     mRenderer = NULL;
     29     mDXGIFormat = DXGI_FORMAT_UNKNOWN;
     30 }
     31 
     32 Image11::~Image11()
     33 {
     34     SafeRelease(mStagingTexture);
     35 }
     36 
     37 Image11 *Image11::makeImage11(Image *img)
     38 {
     39     ASSERT(HAS_DYNAMIC_TYPE(rx::Image11*, img));
     40     return static_cast<rx::Image11*>(img);
     41 }
     42 
     43 void Image11::generateMipmap(GLuint clientVersion, Image11 *dest, Image11 *src)
     44 {
     45     ASSERT(src->getDXGIFormat() == dest->getDXGIFormat());
     46     ASSERT(src->getWidth() == 1 || src->getWidth() / 2 == dest->getWidth());
     47     ASSERT(src->getHeight() == 1 || src->getHeight() / 2 == dest->getHeight());
     48 
     49     MipGenerationFunction mipFunction = d3d11::GetMipGenerationFunction(src->getDXGIFormat());
     50     ASSERT(mipFunction != NULL);
     51 
     52     D3D11_MAPPED_SUBRESOURCE destMapped;
     53     HRESULT destMapResult = dest->map(D3D11_MAP_WRITE, &destMapped);
     54     if (FAILED(destMapResult))
     55     {
     56         ERR("Failed to map destination image for mip map generation. HRESULT:0x%X", destMapResult);
     57         return;
     58     }
     59 
     60     D3D11_MAPPED_SUBRESOURCE srcMapped;
     61     HRESULT srcMapResult = src->map(D3D11_MAP_READ, &srcMapped);
     62     if (FAILED(srcMapResult))
     63     {
     64         ERR("Failed to map source image for mip map generation. HRESULT:0x%X", srcMapResult);
     65 
     66         dest->unmap();
     67         return;
     68     }
     69 
     70     const unsigned char *sourceData = reinterpret_cast<const unsigned char*>(srcMapped.pData);
     71     unsigned char *destData = reinterpret_cast<unsigned char*>(destMapped.pData);
     72 
     73     mipFunction(src->getWidth(), src->getHeight(), src->getDepth(), sourceData, srcMapped.RowPitch, srcMapped.DepthPitch,
     74                 destData, destMapped.RowPitch, destMapped.DepthPitch);
     75 
     76     dest->unmap();
     77     src->unmap();
     78 
     79     dest->markDirty();
     80 }
     81 
     82 bool Image11::isDirty() const
     83 {
     84     // Make sure that this image is marked as dirty even if the staging texture hasn't been created yet
     85     // if initialization is required before use.
     86     return (mDirty && (mStagingTexture || gl_d3d11::RequiresTextureDataInitialization(mInternalFormat)));
     87 }
     88 
     89 bool Image11::copyToStorage(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
     90 {
     91     TextureStorage11_2D *storage11 = TextureStorage11_2D::makeTextureStorage11_2D(storage->getStorageInstance());
     92     return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, 0, xoffset, yoffset, 0, width, height, 1);
     93 }
     94 
     95 bool Image11::copyToStorage(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
     96 {
     97     TextureStorage11_Cube *storage11 = TextureStorage11_Cube::makeTextureStorage11_Cube(storage->getStorageInstance());
     98     return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, face, xoffset, yoffset, 0, width, height, 1);
     99 }
    100 
    101 bool Image11::copyToStorage(TextureStorageInterface3D *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
    102 {
    103     TextureStorage11_3D *storage11 = TextureStorage11_3D::makeTextureStorage11_3D(storage->getStorageInstance());
    104     return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, 0, xoffset, yoffset, zoffset, width, height, depth);
    105 }
    106 
    107 bool Image11::copyToStorage(TextureStorageInterface2DArray *storage, int level, GLint xoffset, GLint yoffset, GLint arrayLayer, GLsizei width, GLsizei height)
    108 {
    109     TextureStorage11_2DArray *storage11 = TextureStorage11_2DArray::makeTextureStorage11_2DArray(storage->getStorageInstance());
    110     return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, arrayLayer, xoffset, yoffset, 0, width, height, 1);
    111 }
    112 
    113 bool Image11::redefine(Renderer *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease)
    114 {
    115     if (mWidth != width ||
    116         mHeight != height ||
    117         mInternalFormat != internalformat ||
    118         forceRelease)
    119     {
    120         mRenderer = Renderer11::makeRenderer11(renderer);
    121         GLuint clientVersion = mRenderer->getCurrentClientVersion();
    122 
    123         mWidth = width;
    124         mHeight = height;
    125         mDepth = depth;
    126         mInternalFormat = internalformat;
    127         mTarget = target;
    128 
    129         // compute the d3d format that will be used
    130         mDXGIFormat = gl_d3d11::GetTexFormat(internalformat, clientVersion);
    131         mActualFormat = d3d11_gl::GetInternalFormat(mDXGIFormat, clientVersion);
    132         mRenderable = gl_d3d11::GetRTVFormat(internalformat, clientVersion) != DXGI_FORMAT_UNKNOWN;
    133 
    134         SafeRelease(mStagingTexture);
    135         mDirty = gl_d3d11::RequiresTextureDataInitialization(mInternalFormat);
    136 
    137         return true;
    138     }
    139 
    140     return false;
    141 }
    142 
    143 DXGI_FORMAT Image11::getDXGIFormat() const
    144 {
    145     // this should only happen if the image hasn't been redefined first
    146     // which would be a bug by the caller
    147     ASSERT(mDXGIFormat != DXGI_FORMAT_UNKNOWN);
    148 
    149     return mDXGIFormat;
    150 }
    151 
    152 // Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
    153 // into the target pixel rectangle.
    154 void Image11::loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
    155                        GLint unpackAlignment, GLenum type, const void *input)
    156 {
    157     GLuint clientVersion = mRenderer->getCurrentClientVersion();
    158     GLsizei inputRowPitch = gl::GetRowPitch(mInternalFormat, type, clientVersion, width, unpackAlignment);
    159     GLsizei inputDepthPitch = gl::GetDepthPitch(mInternalFormat, type, clientVersion, width, height, unpackAlignment);
    160     GLuint outputPixelSize = d3d11::GetFormatPixelBytes(mDXGIFormat);
    161 
    162     LoadImageFunction loadFunction = d3d11::GetImageLoadFunction(mInternalFormat, type, clientVersion);
    163     ASSERT(loadFunction != NULL);
    164 
    165     D3D11_MAPPED_SUBRESOURCE mappedImage;
    166     HRESULT result = map(D3D11_MAP_WRITE, &mappedImage);
    167     if (FAILED(result))
    168     {
    169         ERR("Could not map image for loading.");
    170         return;
    171     }
    172 
    173     void* offsetMappedData = (void*)((BYTE *)mappedImage.pData + (yoffset * mappedImage.RowPitch + xoffset * outputPixelSize + zoffset * mappedImage.DepthPitch));
    174     loadFunction(width, height, depth, input, inputRowPitch, inputDepthPitch, offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch);
    175 
    176     unmap();
    177 }
    178 
    179 void Image11::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
    180                                  const void *input)
    181 {
    182     GLuint clientVersion = mRenderer->getCurrentClientVersion();
    183     GLsizei inputRowPitch = gl::GetRowPitch(mInternalFormat, GL_UNSIGNED_BYTE, clientVersion, width, 1);
    184     GLsizei inputDepthPitch = gl::GetDepthPitch(mInternalFormat, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
    185 
    186     GLuint outputPixelSize = d3d11::GetFormatPixelBytes(mDXGIFormat);
    187     GLuint outputBlockWidth = d3d11::GetBlockWidth(mDXGIFormat);
    188     GLuint outputBlockHeight = d3d11::GetBlockHeight(mDXGIFormat);
    189 
    190     ASSERT(xoffset % outputBlockWidth == 0);
    191     ASSERT(yoffset % outputBlockHeight == 0);
    192 
    193     LoadImageFunction loadFunction = d3d11::GetImageLoadFunction(mInternalFormat, GL_UNSIGNED_BYTE, clientVersion);
    194     ASSERT(loadFunction != NULL);
    195 
    196     D3D11_MAPPED_SUBRESOURCE mappedImage;
    197     HRESULT result = map(D3D11_MAP_WRITE, &mappedImage);
    198     if (FAILED(result))
    199     {
    200         ERR("Could not map image for loading.");
    201         return;
    202     }
    203 
    204     void* offsetMappedData = (void*)((BYTE*)mappedImage.pData + ((yoffset / outputBlockHeight) * mappedImage.RowPitch +
    205                                                                  (xoffset / outputBlockWidth) * outputPixelSize +
    206                                                                  zoffset * mappedImage.DepthPitch));
    207 
    208     loadFunction(width, height, depth, input, inputRowPitch, inputDepthPitch,
    209                  offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch);
    210 
    211     unmap();
    212 }
    213 
    214 void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
    215 {
    216     gl::FramebufferAttachment *colorbuffer = source->getReadColorbuffer();
    217 
    218     if (colorbuffer && colorbuffer->getActualFormat() == mActualFormat)
    219     {
    220         // No conversion needed-- use copyback fastpath
    221         ID3D11Texture2D *colorBufferTexture = NULL;
    222         unsigned int subresourceIndex = 0;
    223 
    224         if (mRenderer->getRenderTargetResource(colorbuffer, &subresourceIndex, &colorBufferTexture))
    225         {
    226             D3D11_TEXTURE2D_DESC textureDesc;
    227             colorBufferTexture->GetDesc(&textureDesc);
    228 
    229             ID3D11Device *device = mRenderer->getDevice();
    230             ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
    231 
    232             ID3D11Texture2D* srcTex = NULL;
    233             if (textureDesc.SampleDesc.Count > 1)
    234             {
    235                 D3D11_TEXTURE2D_DESC resolveDesc;
    236                 resolveDesc.Width = textureDesc.Width;
    237                 resolveDesc.Height = textureDesc.Height;
    238                 resolveDesc.MipLevels = 1;
    239                 resolveDesc.ArraySize = 1;
    240                 resolveDesc.Format = textureDesc.Format;
    241                 resolveDesc.SampleDesc.Count = 1;
    242                 resolveDesc.SampleDesc.Quality = 0;
    243                 resolveDesc.Usage = D3D11_USAGE_DEFAULT;
    244                 resolveDesc.BindFlags = 0;
    245                 resolveDesc.CPUAccessFlags = 0;
    246                 resolveDesc.MiscFlags = 0;
    247 
    248                 HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex);
    249                 if (FAILED(result))
    250                 {
    251                     ERR("Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.", result);
    252                     return;
    253                 }
    254 
    255                 deviceContext->ResolveSubresource(srcTex, 0, colorBufferTexture, subresourceIndex, textureDesc.Format);
    256                 subresourceIndex = 0;
    257             }
    258             else
    259             {
    260                 srcTex = colorBufferTexture;
    261                 srcTex->AddRef();
    262             }
    263 
    264             D3D11_BOX srcBox;
    265             srcBox.left = x;
    266             srcBox.right = x + width;
    267             srcBox.top = y;
    268             srcBox.bottom = y + height;
    269             srcBox.front = 0;
    270             srcBox.back = 1;
    271 
    272             deviceContext->CopySubresourceRegion(mStagingTexture, 0, xoffset, yoffset, zoffset, srcTex, subresourceIndex, &srcBox);
    273 
    274             SafeRelease(srcTex);
    275             SafeRelease(colorBufferTexture);
    276         }
    277     }
    278     else
    279     {
    280         // This format requires conversion, so we must copy the texture to staging and manually convert via readPixels
    281         D3D11_MAPPED_SUBRESOURCE mappedImage;
    282         HRESULT result = map(D3D11_MAP_WRITE, &mappedImage);
    283         if (FAILED(result))
    284         {
    285             ERR("Failed to map texture for Image11::copy, HRESULT: 0x%X.", result);
    286             return;
    287         }
    288 
    289         // determine the offset coordinate into the destination buffer
    290         GLuint clientVersion = mRenderer->getCurrentClientVersion();
    291         GLsizei rowOffset = gl::GetPixelBytes(mActualFormat, clientVersion) * xoffset;
    292         void *dataOffset = static_cast<unsigned char*>(mappedImage.pData) + mappedImage.RowPitch * yoffset + rowOffset + zoffset * mappedImage.DepthPitch;
    293 
    294         GLenum format = gl::GetFormat(mInternalFormat, clientVersion);
    295         GLenum type = gl::GetType(mInternalFormat, clientVersion);
    296 
    297         mRenderer->readPixels(source, x, y, width, height, format, type, mappedImage.RowPitch, gl::PixelPackState(), dataOffset);
    298 
    299         unmap();
    300     }
    301 }
    302 
    303 ID3D11Resource *Image11::getStagingTexture()
    304 {
    305     createStagingTexture();
    306 
    307     return mStagingTexture;
    308 }
    309 
    310 unsigned int Image11::getStagingSubresource()
    311 {
    312     createStagingTexture();
    313 
    314     return mStagingSubresource;
    315 }
    316 
    317 void Image11::createStagingTexture()
    318 {
    319     if (mStagingTexture)
    320     {
    321         return;
    322     }
    323 
    324     const DXGI_FORMAT dxgiFormat = getDXGIFormat();
    325 
    326     if (mWidth > 0 && mHeight > 0 && mDepth > 0)
    327     {
    328         ID3D11Device *device = mRenderer->getDevice();
    329         HRESULT result;
    330 
    331         int lodOffset = 1;
    332         GLsizei width = mWidth;
    333         GLsizei height = mHeight;
    334 
    335         // adjust size if needed for compressed textures
    336         d3d11::MakeValidSize(false, dxgiFormat, &width, &height, &lodOffset);
    337 
    338         if (mTarget == GL_TEXTURE_3D)
    339         {
    340             ID3D11Texture3D *newTexture = NULL;
    341 
    342             D3D11_TEXTURE3D_DESC desc;
    343             desc.Width = width;
    344             desc.Height = height;
    345             desc.Depth = mDepth;
    346             desc.MipLevels = lodOffset + 1;
    347             desc.Format = dxgiFormat;
    348             desc.Usage = D3D11_USAGE_STAGING;
    349             desc.BindFlags = 0;
    350             desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
    351             desc.MiscFlags = 0;
    352 
    353             if (gl_d3d11::RequiresTextureDataInitialization(mInternalFormat))
    354             {
    355                 std::vector<D3D11_SUBRESOURCE_DATA> initialData;
    356                 std::vector< std::vector<BYTE> > textureData;
    357                 d3d11::GenerateInitialTextureData(mInternalFormat, mRenderer->getCurrentClientVersion(), width, height,
    358                                                   mDepth, lodOffset + 1, &initialData, &textureData);
    359 
    360                 result = device->CreateTexture3D(&desc, initialData.data(), &newTexture);
    361             }
    362             else
    363             {
    364                 result = device->CreateTexture3D(&desc, NULL, &newTexture);
    365             }
    366 
    367             if (FAILED(result))
    368             {
    369                 ASSERT(result == E_OUTOFMEMORY);
    370                 ERR("Creating image failed.");
    371                 return gl::error(GL_OUT_OF_MEMORY);
    372             }
    373 
    374             mStagingTexture = newTexture;
    375             mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1);
    376         }
    377         else if (mTarget == GL_TEXTURE_2D || mTarget == GL_TEXTURE_2D_ARRAY || mTarget == GL_TEXTURE_CUBE_MAP)
    378         {
    379             ID3D11Texture2D *newTexture = NULL;
    380 
    381             D3D11_TEXTURE2D_DESC desc;
    382             desc.Width = width;
    383             desc.Height = height;
    384             desc.MipLevels = lodOffset + 1;
    385             desc.ArraySize = 1;
    386             desc.Format = dxgiFormat;
    387             desc.SampleDesc.Count = 1;
    388             desc.SampleDesc.Quality = 0;
    389             desc.Usage = D3D11_USAGE_STAGING;
    390             desc.BindFlags = 0;
    391             desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
    392             desc.MiscFlags = 0;
    393 
    394             if (gl_d3d11::RequiresTextureDataInitialization(mInternalFormat))
    395             {
    396                 std::vector<D3D11_SUBRESOURCE_DATA> initialData;
    397                 std::vector< std::vector<BYTE> > textureData;
    398                 d3d11::GenerateInitialTextureData(mInternalFormat, mRenderer->getCurrentClientVersion(), width, height,
    399                                                   1, lodOffset + 1, &initialData, &textureData);
    400 
    401                 result = device->CreateTexture2D(&desc, initialData.data(), &newTexture);
    402             }
    403             else
    404             {
    405                 result = device->CreateTexture2D(&desc, NULL, &newTexture);
    406             }
    407 
    408             if (FAILED(result))
    409             {
    410                 ASSERT(result == E_OUTOFMEMORY);
    411                 ERR("Creating image failed.");
    412                 return gl::error(GL_OUT_OF_MEMORY);
    413             }
    414 
    415             mStagingTexture = newTexture;
    416             mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1);
    417         }
    418         else
    419         {
    420             UNREACHABLE();
    421         }
    422     }
    423 
    424     mDirty = false;
    425 }
    426 
    427 HRESULT Image11::map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map)
    428 {
    429     createStagingTexture();
    430 
    431     HRESULT result = E_FAIL;
    432 
    433     if (mStagingTexture)
    434     {
    435         ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
    436         result = deviceContext->Map(mStagingTexture, mStagingSubresource, mapType, 0, map);
    437 
    438         // this can fail if the device is removed (from TDR)
    439         if (d3d11::isDeviceLostError(result))
    440         {
    441             mRenderer->notifyDeviceLost();
    442         }
    443         else if (SUCCEEDED(result))
    444         {
    445             mDirty = true;
    446         }
    447     }
    448 
    449     return result;
    450 }
    451 
    452 void Image11::unmap()
    453 {
    454     if (mStagingTexture)
    455     {
    456         ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
    457         deviceContext->Unmap(mStagingTexture, mStagingSubresource);
    458     }
    459 }
    460 
    461 }
    462