void MyD3DAssets::readTexture(ID3D11Texture2D *inputTexture, Bitmap &result) { ID3D11Texture2D *stagingTexture = getStagingTexture(inputTexture); D3D11_TEXTURE2D_DESC desc; stagingTexture->GetDesc(&desc); if (result.getWidth() != desc.Width || result.getHeight() != desc.Height) result.allocate(desc.Width, desc.Height); for (auto &p : result) p.value = ml::vec4uc(50, 100, 150, 255); context->base->CopyResource(stagingTexture, inputTexture); D3D11_MAPPED_SUBRESOURCE resource; UINT subresource = D3D11CalcSubresource(0, 0, 0); HRESULT hr = context->base->Map(stagingTexture, subresource, D3D11_MAP_READ, 0, &resource); const BYTE *data = (BYTE *)resource.pData; for (UINT y = 0; y < desc.Height; y++) { memcpy(&result(0U, y), data + resource.RowPitch * y, desc.Width * sizeof(ml::vec4uc)); } context->base->Unmap(stagingTexture, subresource); }
gl::Error Image11::map(const gl::Context *context, D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map) { // We must recover from the TextureStorage if necessary, even for D3D11_MAP_WRITE. ANGLE_TRY(recoverFromAssociatedStorage(context)); const TextureHelper11 *stagingTexture = nullptr; unsigned int subresourceIndex = 0; ANGLE_TRY(getStagingTexture(&stagingTexture, &subresourceIndex)); ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); ASSERT(stagingTexture && stagingTexture->valid()); HRESULT result = deviceContext->Map(stagingTexture->get(), subresourceIndex, mapType, 0, map); if (FAILED(result)) { // this can fail if the device is removed (from TDR) if (d3d11::isDeviceLostError(result)) { mRenderer->notifyDeviceLost(); } return gl::OutOfMemory() << "Failed to map staging texture, " << gl::FmtHR(result); } mDirty = true; return gl::NoError(); }
gl::Error Image11::copyWithoutConversion(const gl::Offset &destOffset, const gl::Box &sourceArea, const TextureHelper11 &textureHelper, UINT sourceSubResource) { // No conversion needed-- use copyback fastpath const TextureHelper11 *stagingTexture = nullptr; unsigned int stagingSubresourceIndex = 0; ANGLE_TRY(getStagingTexture(&stagingTexture, &stagingSubresourceIndex)); ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); const gl::Extents &extents = textureHelper.getExtents(); D3D11_BOX srcBox; srcBox.left = sourceArea.x; srcBox.right = sourceArea.x + sourceArea.width; srcBox.top = sourceArea.y; srcBox.bottom = sourceArea.y + sourceArea.height; srcBox.front = sourceArea.z; srcBox.back = sourceArea.z + sourceArea.depth; if (textureHelper.is2D() && textureHelper.getSampleCount() > 1) { D3D11_TEXTURE2D_DESC resolveDesc; resolveDesc.Width = extents.width; resolveDesc.Height = extents.height; resolveDesc.MipLevels = 1; resolveDesc.ArraySize = 1; resolveDesc.Format = textureHelper.getFormat(); resolveDesc.SampleDesc.Count = 1; resolveDesc.SampleDesc.Quality = 0; resolveDesc.Usage = D3D11_USAGE_DEFAULT; resolveDesc.BindFlags = 0; resolveDesc.CPUAccessFlags = 0; resolveDesc.MiscFlags = 0; d3d11::Texture2D resolveTex; ANGLE_TRY(mRenderer->allocateResource(resolveDesc, &resolveTex)); deviceContext->ResolveSubresource(resolveTex.get(), 0, textureHelper.get(), sourceSubResource, textureHelper.getFormat()); deviceContext->CopySubresourceRegion(stagingTexture->get(), stagingSubresourceIndex, destOffset.x, destOffset.y, destOffset.z, resolveTex.get(), 0, &srcBox); } else { deviceContext->CopySubresourceRegion(stagingTexture->get(), stagingSubresourceIndex, destOffset.x, destOffset.y, destOffset.z, textureHelper.get(), sourceSubResource, &srcBox); } mDirty = true; return gl::NoError(); }
bool Image11::updateSurface(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, bool mipped) { TextureStorage11_2D *storage11 = TextureStorage11_2D::makeTextureStorage11_2D(storage->getStorageInstance()); bool ret = storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, 0, xoffset, yoffset, width, height, mipped); /* blamb: attempt to reduce memory */ if (mStagingTexture) { mStagingTexture->Release(); mStagingTexture = NULL; } return ret; }
gl::Error Image11::copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion) { TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(storage); // If an app's behavior results in an Image11 copying its data to/from to a TextureStorage multiple times, // then we should just keep the staging texture around to prevent the copying from impacting perf. // We allow the Image11 to copy its data to/from TextureStorage once. // This accounts for an app making a late call to glGenerateMipmap. bool attemptToReleaseStagingTexture = (mRecoveredFromStorageCount < 2); if (attemptToReleaseStagingTexture) { // If another image is relying on this Storage for its data, then we must let it recover its data before we overwrite it. gl::Error error = storage11->releaseAssociatedImage(index, this); if (error.isError()) { return error; } } ID3D11Resource *stagingTexture = NULL; unsigned int stagingSubresourceIndex = 0; gl::Error error = getStagingTexture(&stagingTexture, &stagingSubresourceIndex); if (error.isError()) { return error; } error = storage11->updateSubresourceLevel(stagingTexture, stagingSubresourceIndex, index, region); if (error.isError()) { return error; } // Once the image data has been copied into the Storage, we can release it locally. if (attemptToReleaseStagingTexture) { storage11->associateImage(this, index); releaseStagingTexture(); mRecoverFromStorage = true; mAssociatedStorage = storage11; mAssociatedImageIndex = index; } return gl::Error(GL_NO_ERROR); }
gl::Error Image11::copyToStorage(const gl::Context *context, TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion) { TextureStorage11 *storage11 = GetAs<TextureStorage11>(storage); // If an app's behavior results in an Image11 copying its data to/from to a TextureStorage // multiple times, then we should just keep the staging texture around to prevent the copying // from impacting perf. We allow the Image11 to copy its data to/from TextureStorage once. This // accounts for an app making a late call to glGenerateMipmap. bool attemptToReleaseStagingTexture = (mRecoveredFromStorageCount < 2); if (attemptToReleaseStagingTexture) { // If another image is relying on this Storage for its data, then we must let it recover its // data before we overwrite it. ANGLE_TRY(storage11->releaseAssociatedImage(context, index, this)); } const TextureHelper11 *stagingTexture = nullptr; unsigned int stagingSubresourceIndex = 0; ANGLE_TRY(getStagingTexture(&stagingTexture, &stagingSubresourceIndex)); ANGLE_TRY(storage11->updateSubresourceLevel(context, *stagingTexture, stagingSubresourceIndex, index, region)); // Once the image data has been copied into the Storage, we can release it locally. if (attemptToReleaseStagingTexture) { storage11->associateImage(this, index); releaseStagingTexture(); mRecoverFromStorage = true; mAssociatedStorage = storage11; mAssociatedImageIndex = index; } return gl::NoError(); }
gl::Error Image11::map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map) { // We must recover from the TextureStorage if necessary, even for D3D11_MAP_WRITE. gl::Error error = recoverFromAssociatedStorage(); if (error.isError()) { return error; } ID3D11Resource *stagingTexture = NULL; unsigned int subresourceIndex = 0; error = getStagingTexture(&stagingTexture, &subresourceIndex); if (error.isError()) { return error; } ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); ASSERT(mStagingTexture); HRESULT result = deviceContext->Map(stagingTexture, subresourceIndex, mapType, 0, map); // this can fail if the device is removed (from TDR) if (d3d11::isDeviceLostError(result)) { mRenderer->notifyDeviceLost(); } else if (FAILED(result)) { return gl::Error(GL_OUT_OF_MEMORY, "Failed to map staging texture, result: 0x%X.", result); } mDirty = true; return gl::Error(GL_NO_ERROR); }
gl::Error Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, ID3D11Texture2D *source, UINT sourceSubResource) { D3D11_TEXTURE2D_DESC textureDesc; source->GetDesc(&textureDesc); if (textureDesc.Format == mDXGIFormat) { // No conversion needed-- use copyback fastpath ID3D11Resource *stagingTexture = NULL; unsigned int stagingSubresourceIndex = 0; gl::Error error = getStagingTexture(&stagingTexture, &stagingSubresourceIndex); if (error.isError()) { return error; } ID3D11Device *device = mRenderer->getDevice(); ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); UINT subresourceAfterResolve = sourceSubResource; ID3D11Texture2D* srcTex = NULL; if (textureDesc.SampleDesc.Count > 1) { D3D11_TEXTURE2D_DESC resolveDesc; resolveDesc.Width = textureDesc.Width; resolveDesc.Height = textureDesc.Height; resolveDesc.MipLevels = 1; resolveDesc.ArraySize = 1; resolveDesc.Format = textureDesc.Format; resolveDesc.SampleDesc.Count = 1; resolveDesc.SampleDesc.Quality = 0; resolveDesc.Usage = D3D11_USAGE_DEFAULT; resolveDesc.BindFlags = 0; resolveDesc.CPUAccessFlags = 0; resolveDesc.MiscFlags = 0; HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex); if (FAILED(result)) { return gl::Error(GL_OUT_OF_MEMORY, "Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.", result); } deviceContext->ResolveSubresource(srcTex, 0, source, sourceSubResource, textureDesc.Format); subresourceAfterResolve = 0; } else { srcTex = source; } D3D11_BOX srcBox; srcBox.left = sourceArea.x; srcBox.right = sourceArea.x + sourceArea.width; srcBox.top = sourceArea.y; srcBox.bottom = sourceArea.y + sourceArea.height; srcBox.front = 0; srcBox.back = 1; deviceContext->CopySubresourceRegion(stagingTexture, stagingSubresourceIndex, xoffset, yoffset, zoffset, srcTex, subresourceAfterResolve, &srcBox); if (textureDesc.SampleDesc.Count > 1) { SafeRelease(srcTex); } } else { // This format requires conversion, so we must copy the texture to staging and manually convert via readPixels D3D11_MAPPED_SUBRESOURCE mappedImage; gl::Error error = map(D3D11_MAP_WRITE, &mappedImage); if (error.isError()) { return error; } // determine the offset coordinate into the destination buffer GLsizei rowOffset = gl::GetInternalFormatInfo(mActualFormat).pixelBytes * xoffset; uint8_t *dataOffset = static_cast<uint8_t*>(mappedImage.pData) + mappedImage.RowPitch * yoffset + rowOffset + zoffset * mappedImage.DepthPitch; const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat); error = mRenderer->readTextureData(source, sourceSubResource, sourceArea, formatInfo.format, formatInfo.type, mappedImage.RowPitch, gl::PixelPackState(), dataOffset); unmap(); if (error.isError()) { return error; } } mDirty = true; return gl::Error(GL_NO_ERROR); }
bool Image11::copyToStorage(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) { TextureStorage11_Cube *storage11 = TextureStorage11_Cube::makeTextureStorage11_Cube(storage->getStorageInstance()); return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, face, xoffset, yoffset, 0, width, height, 1); }
bool Image11::copyToStorage(TextureStorageInterface2DArray *storage, int level, GLint xoffset, GLint yoffset, GLint arrayLayer, GLsizei width, GLsizei height) { TextureStorage11_2DArray *storage11 = TextureStorage11_2DArray::makeTextureStorage11_2DArray(storage->getStorageInstance()); return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, arrayLayer, xoffset, yoffset, 0, width, height, 1); }
bool Image11::copyToStorage(TextureStorageInterface3D *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth) { TextureStorage11_3D *storage11 = TextureStorage11_3D::makeTextureStorage11_3D(storage->getStorageInstance()); return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, 0, xoffset, yoffset, zoffset, width, height, depth); }
gl::Error Image11::copyWithoutConversion(const gl::Offset &destOffset, const gl::Box &sourceArea, const TextureHelper11 &textureHelper, UINT sourceSubResource) { // No conversion needed-- use copyback fastpath ID3D11Resource *stagingTexture = nullptr; unsigned int stagingSubresourceIndex = 0; gl::Error error = getStagingTexture(&stagingTexture, &stagingSubresourceIndex); if (error.isError()) { return error; } ID3D11Device *device = mRenderer->getDevice(); ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); UINT subresourceAfterResolve = sourceSubResource; ID3D11Resource *srcTex = nullptr; const gl::Extents &extents = textureHelper.getExtents(); bool needResolve = (textureHelper.getTextureType() == GL_TEXTURE_2D && textureHelper.getSampleCount() > 1); if (needResolve) { D3D11_TEXTURE2D_DESC resolveDesc; resolveDesc.Width = extents.width; resolveDesc.Height = extents.height; resolveDesc.MipLevels = 1; resolveDesc.ArraySize = 1; resolveDesc.Format = textureHelper.getFormat(); resolveDesc.SampleDesc.Count = 1; resolveDesc.SampleDesc.Quality = 0; resolveDesc.Usage = D3D11_USAGE_DEFAULT; resolveDesc.BindFlags = 0; resolveDesc.CPUAccessFlags = 0; resolveDesc.MiscFlags = 0; ID3D11Texture2D *srcTex2D = NULL; HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex2D); if (FAILED(result)) { return gl::Error(GL_OUT_OF_MEMORY, "Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.", result); } srcTex = srcTex2D; deviceContext->ResolveSubresource(srcTex, 0, textureHelper.getTexture2D(), sourceSubResource, textureHelper.getFormat()); subresourceAfterResolve = 0; } else { srcTex = textureHelper.getResource(); } D3D11_BOX srcBox; srcBox.left = sourceArea.x; srcBox.right = sourceArea.x + sourceArea.width; srcBox.top = sourceArea.y; srcBox.bottom = sourceArea.y + sourceArea.height; srcBox.front = sourceArea.z; srcBox.back = sourceArea.z + sourceArea.depth; deviceContext->CopySubresourceRegion(stagingTexture, stagingSubresourceIndex, destOffset.x, destOffset.y, destOffset.z, srcTex, subresourceAfterResolve, &srcBox); if (needResolve) { SafeRelease(srcTex); } mDirty = true; return gl::Error(GL_NO_ERROR); }
gl::Error Image11::copy(const gl::Offset &destOffset, const gl::Box &sourceArea, ID3D11Resource *source, UINT sourceSubResource) { D3D11_RESOURCE_DIMENSION dim; source->GetType(&dim); DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN; gl::Extents extents; UINT sampleCount = 0; ID3D11Texture2D *source2D = NULL; if (dim == D3D11_RESOURCE_DIMENSION_TEXTURE2D) { D3D11_TEXTURE2D_DESC textureDesc2D; source2D = d3d11::DynamicCastComObject<ID3D11Texture2D>(source); ASSERT(source2D); source2D->GetDesc(&textureDesc2D); format = textureDesc2D.Format; extents = gl::Extents(textureDesc2D.Width, textureDesc2D.Height, 1); sampleCount = textureDesc2D.SampleDesc.Count; } else if (dim == D3D11_RESOURCE_DIMENSION_TEXTURE3D) { D3D11_TEXTURE3D_DESC textureDesc3D; ID3D11Texture3D *source3D = d3d11::DynamicCastComObject<ID3D11Texture3D>(source); ASSERT(source3D); source3D->GetDesc(&textureDesc3D); format = textureDesc3D.Format; extents = gl::Extents(textureDesc3D.Width, textureDesc3D.Height, textureDesc3D.Depth); sampleCount = 1; } else { UNREACHABLE(); } if (format == mDXGIFormat) { // No conversion needed-- use copyback fastpath ID3D11Resource *stagingTexture = NULL; unsigned int stagingSubresourceIndex = 0; gl::Error error = getStagingTexture(&stagingTexture, &stagingSubresourceIndex); if (error.isError()) { return error; } ID3D11Device *device = mRenderer->getDevice(); ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); UINT subresourceAfterResolve = sourceSubResource; ID3D11Resource *srcTex = NULL; bool needResolve = (dim == D3D11_RESOURCE_DIMENSION_TEXTURE2D && sampleCount > 1); if (needResolve) { D3D11_TEXTURE2D_DESC resolveDesc; resolveDesc.Width = extents.width; resolveDesc.Height = extents.height; resolveDesc.MipLevels = 1; resolveDesc.ArraySize = 1; resolveDesc.Format = format; resolveDesc.SampleDesc.Count = 1; resolveDesc.SampleDesc.Quality = 0; resolveDesc.Usage = D3D11_USAGE_DEFAULT; resolveDesc.BindFlags = 0; resolveDesc.CPUAccessFlags = 0; resolveDesc.MiscFlags = 0; ID3D11Texture2D *srcTex2D = NULL; HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex2D); if (FAILED(result)) { return gl::Error(GL_OUT_OF_MEMORY, "Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.", result); } srcTex = srcTex2D; deviceContext->ResolveSubresource(srcTex, 0, source, sourceSubResource, format); subresourceAfterResolve = 0; } else { srcTex = source; } D3D11_BOX srcBox; srcBox.left = sourceArea.x; srcBox.right = sourceArea.x + sourceArea.width; srcBox.top = sourceArea.y; srcBox.bottom = sourceArea.y + sourceArea.height; srcBox.front = sourceArea.z; srcBox.back = sourceArea.z + sourceArea.depth; deviceContext->CopySubresourceRegion(stagingTexture, stagingSubresourceIndex, destOffset.x, destOffset.y, destOffset.z, srcTex, subresourceAfterResolve, &srcBox); if (needResolve) { SafeRelease(srcTex); } } else { // This format requires conversion, so we must copy the texture to staging and manually convert via readPixels D3D11_MAPPED_SUBRESOURCE mappedImage; gl::Error error = map(D3D11_MAP_WRITE, &mappedImage); if (error.isError()) { return error; } // determine the offset coordinate into the destination buffer const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mDXGIFormat); GLsizei rowOffset = dxgiFormatInfo.pixelBytes * destOffset.x; uint8_t *dataOffset = static_cast<uint8_t*>(mappedImage.pData) + mappedImage.RowPitch * destOffset.y + rowOffset + destOffset.z * mappedImage.DepthPitch; const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat); // Currently in ANGLE, the source data may only need to be converted if the source is the current framebuffer // and OpenGL ES framebuffers must be 2D textures therefore we should not need to convert 3D textures between different formats. ASSERT(dim == D3D11_RESOURCE_DIMENSION_TEXTURE2D); ASSERT(sourceArea.z == 0 && sourceArea.depth == 1); gl::Rectangle sourceRect(sourceArea.x, sourceArea.y, sourceArea.width, sourceArea.height); error = mRenderer->readTextureData(source2D, sourceSubResource, sourceRect, formatInfo.format, formatInfo.type, mappedImage.RowPitch, gl::PixelPackState(), dataOffset); unmap(); if (error.isError()) { return error; } } mDirty = true; return gl::Error(GL_NO_ERROR); }