1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/2d/SourceSurfaceD2DTarget.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,315 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "SourceSurfaceD2DTarget.h" 1.10 +#include "Logging.h" 1.11 +#include "DrawTargetD2D.h" 1.12 +#include "Tools.h" 1.13 + 1.14 +#include <algorithm> 1.15 + 1.16 +namespace mozilla { 1.17 +namespace gfx { 1.18 + 1.19 +SourceSurfaceD2DTarget::SourceSurfaceD2DTarget(DrawTargetD2D* aDrawTarget, 1.20 + ID3D10Texture2D* aTexture, 1.21 + SurfaceFormat aFormat) 1.22 + : mDrawTarget(aDrawTarget) 1.23 + , mTexture(aTexture) 1.24 + , mFormat(aFormat) 1.25 + , mOwnsCopy(false) 1.26 +{ 1.27 +} 1.28 + 1.29 +SourceSurfaceD2DTarget::~SourceSurfaceD2DTarget() 1.30 +{ 1.31 + // We don't need to do anything special here to notify our mDrawTarget. It must 1.32 + // already have cleared its mSnapshot field, otherwise this object would 1.33 + // be kept alive. 1.34 + if (mOwnsCopy) { 1.35 + IntSize size = GetSize(); 1.36 + 1.37 + DrawTargetD2D::mVRAMUsageSS -= size.width * size.height * BytesPerPixel(mFormat); 1.38 + } 1.39 +} 1.40 + 1.41 +IntSize 1.42 +SourceSurfaceD2DTarget::GetSize() const 1.43 +{ 1.44 + D3D10_TEXTURE2D_DESC desc; 1.45 + mTexture->GetDesc(&desc); 1.46 + 1.47 + return IntSize(desc.Width, desc.Height); 1.48 +} 1.49 + 1.50 +SurfaceFormat 1.51 +SourceSurfaceD2DTarget::GetFormat() const 1.52 +{ 1.53 + return mFormat; 1.54 +} 1.55 + 1.56 +TemporaryRef<DataSourceSurface> 1.57 +SourceSurfaceD2DTarget::GetDataSurface() 1.58 +{ 1.59 + RefPtr<DataSourceSurfaceD2DTarget> dataSurf = 1.60 + new DataSourceSurfaceD2DTarget(mFormat); 1.61 + 1.62 + D3D10_TEXTURE2D_DESC desc; 1.63 + mTexture->GetDesc(&desc); 1.64 + 1.65 + desc.CPUAccessFlags = D3D10_CPU_ACCESS_READ; 1.66 + desc.Usage = D3D10_USAGE_STAGING; 1.67 + desc.BindFlags = 0; 1.68 + desc.MiscFlags = 0; 1.69 + 1.70 + HRESULT hr = Factory::GetDirect3D10Device()->CreateTexture2D(&desc, nullptr, byRef(dataSurf->mTexture)); 1.71 + 1.72 + if (FAILED(hr)) { 1.73 + gfxDebug() << "Failed to create staging texture for SourceSurface. Code: " << hr; 1.74 + return nullptr; 1.75 + } 1.76 + Factory::GetDirect3D10Device()->CopyResource(dataSurf->mTexture, mTexture); 1.77 + 1.78 + return dataSurf; 1.79 +} 1.80 + 1.81 +void* 1.82 +SourceSurfaceD2DTarget::GetNativeSurface(NativeSurfaceType aType) 1.83 +{ 1.84 + if (aType == NativeSurfaceType::D3D10_TEXTURE) { 1.85 + return static_cast<void*>(mTexture.get()); 1.86 + } 1.87 + return nullptr; 1.88 +} 1.89 + 1.90 +ID3D10ShaderResourceView* 1.91 +SourceSurfaceD2DTarget::GetSRView() 1.92 +{ 1.93 + if (mSRView) { 1.94 + return mSRView; 1.95 + } 1.96 + 1.97 + HRESULT hr = Factory::GetDirect3D10Device()->CreateShaderResourceView(mTexture, nullptr, byRef(mSRView)); 1.98 + 1.99 + if (FAILED(hr)) { 1.100 + gfxWarning() << "Failed to create ShaderResourceView. Code: " << hr; 1.101 + } 1.102 + 1.103 + return mSRView; 1.104 +} 1.105 + 1.106 +void 1.107 +SourceSurfaceD2DTarget::DrawTargetWillChange() 1.108 +{ 1.109 + RefPtr<ID3D10Texture2D> oldTexture = mTexture; 1.110 + 1.111 + D3D10_TEXTURE2D_DESC desc; 1.112 + mTexture->GetDesc(&desc); 1.113 + 1.114 + // Our original texture might implement the keyed mutex flag. We shouldn't 1.115 + // need that here. We actually specifically don't want it since we don't lock 1.116 + // our texture for usage! 1.117 + desc.MiscFlags = 0; 1.118 + 1.119 + // Get a copy of the surface data so the content at snapshot time was saved. 1.120 + Factory::GetDirect3D10Device()->CreateTexture2D(&desc, nullptr, byRef(mTexture)); 1.121 + Factory::GetDirect3D10Device()->CopyResource(mTexture, oldTexture); 1.122 + 1.123 + mBitmap = nullptr; 1.124 + 1.125 + DrawTargetD2D::mVRAMUsageSS += desc.Width * desc.Height * BytesPerPixel(mFormat); 1.126 + mOwnsCopy = true; 1.127 + 1.128 + // We now no longer depend on the source surface content remaining the same. 1.129 + MarkIndependent(); 1.130 +} 1.131 + 1.132 +ID2D1Bitmap* 1.133 +SourceSurfaceD2DTarget::GetBitmap(ID2D1RenderTarget *aRT) 1.134 +{ 1.135 + if (mBitmap) { 1.136 + return mBitmap; 1.137 + } 1.138 + 1.139 + HRESULT hr; 1.140 + D3D10_TEXTURE2D_DESC desc; 1.141 + mTexture->GetDesc(&desc); 1.142 + 1.143 + IntSize size(desc.Width, desc.Height); 1.144 + 1.145 + RefPtr<IDXGISurface> surf; 1.146 + hr = mTexture->QueryInterface((IDXGISurface**)byRef(surf)); 1.147 + 1.148 + if (FAILED(hr)) { 1.149 + gfxWarning() << "Failed to query interface texture to DXGISurface. Code: " << hr; 1.150 + return nullptr; 1.151 + } 1.152 + 1.153 + D2D1_BITMAP_PROPERTIES props = D2D1::BitmapProperties(D2DPixelFormat(mFormat)); 1.154 + hr = aRT->CreateSharedBitmap(IID_IDXGISurface, surf, &props, byRef(mBitmap)); 1.155 + 1.156 + if (FAILED(hr)) { 1.157 + // This seems to happen for SurfaceFormat::A8 sometimes... 1.158 + hr = aRT->CreateBitmap(D2D1::SizeU(desc.Width, desc.Height), 1.159 + D2D1::BitmapProperties(D2DPixelFormat(mFormat)), 1.160 + byRef(mBitmap)); 1.161 + 1.162 + if (FAILED(hr)) { 1.163 + gfxWarning() << "Failed in CreateBitmap. Code: " << hr; 1.164 + return nullptr; 1.165 + } 1.166 + 1.167 + RefPtr<ID2D1RenderTarget> rt; 1.168 + 1.169 + if (mDrawTarget) { 1.170 + rt = mDrawTarget->mRT; 1.171 + } 1.172 + 1.173 + if (!rt) { 1.174 + // Okay, we already separated from our drawtarget. And we're an A8 1.175 + // surface the only way we can get to a bitmap is by creating a 1.176 + // a rendertarget and from there copying to a bitmap! Terrible! 1.177 + RefPtr<IDXGISurface> surface; 1.178 + 1.179 + hr = mTexture->QueryInterface((IDXGISurface**)byRef(surface)); 1.180 + 1.181 + if (FAILED(hr)) { 1.182 + gfxWarning() << "Failed to QI texture to surface."; 1.183 + return nullptr; 1.184 + } 1.185 + 1.186 + D2D1_RENDER_TARGET_PROPERTIES props = 1.187 + D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, D2DPixelFormat(mFormat)); 1.188 + hr = DrawTargetD2D::factory()->CreateDxgiSurfaceRenderTarget(surface, props, byRef(rt)); 1.189 + 1.190 + if (FAILED(hr)) { 1.191 + gfxWarning() << "Failed to create D2D render target for texture."; 1.192 + return nullptr; 1.193 + } 1.194 + } 1.195 + 1.196 + mBitmap->CopyFromRenderTarget(nullptr, rt, nullptr); 1.197 + return mBitmap; 1.198 + } 1.199 + 1.200 + return mBitmap; 1.201 +} 1.202 + 1.203 +void 1.204 +SourceSurfaceD2DTarget::MarkIndependent() 1.205 +{ 1.206 + if (mDrawTarget) { 1.207 + MOZ_ASSERT(mDrawTarget->mSnapshot == this); 1.208 + mDrawTarget->mSnapshot = nullptr; 1.209 + mDrawTarget = nullptr; 1.210 + } 1.211 +} 1.212 + 1.213 +DataSourceSurfaceD2DTarget::DataSourceSurfaceD2DTarget(SurfaceFormat aFormat) 1.214 + : mFormat(aFormat) 1.215 + , mMapped(false) 1.216 +{ 1.217 +} 1.218 + 1.219 +DataSourceSurfaceD2DTarget::~DataSourceSurfaceD2DTarget() 1.220 +{ 1.221 + if (mMapped) { 1.222 + mTexture->Unmap(0); 1.223 + } 1.224 +} 1.225 + 1.226 +IntSize 1.227 +DataSourceSurfaceD2DTarget::GetSize() const 1.228 +{ 1.229 + D3D10_TEXTURE2D_DESC desc; 1.230 + mTexture->GetDesc(&desc); 1.231 + 1.232 + return IntSize(desc.Width, desc.Height); 1.233 +} 1.234 + 1.235 +SurfaceFormat 1.236 +DataSourceSurfaceD2DTarget::GetFormat() const 1.237 +{ 1.238 + return mFormat; 1.239 +} 1.240 + 1.241 +uint8_t* 1.242 +DataSourceSurfaceD2DTarget::GetData() 1.243 +{ 1.244 + EnsureMapped(); 1.245 + 1.246 + return (unsigned char*)mMap.pData; 1.247 +} 1.248 + 1.249 +int32_t 1.250 +DataSourceSurfaceD2DTarget::Stride() 1.251 +{ 1.252 + EnsureMapped(); 1.253 + return mMap.RowPitch; 1.254 +} 1.255 + 1.256 +bool 1.257 +DataSourceSurfaceD2DTarget::Map(MapType aMapType, MappedSurface *aMappedSurface) 1.258 +{ 1.259 + // DataSourceSurfaces used with the new Map API should not be used with GetData!! 1.260 + MOZ_ASSERT(!mMapped); 1.261 + MOZ_ASSERT(!mIsMapped); 1.262 + 1.263 + if (!mTexture) { 1.264 + return false; 1.265 + } 1.266 + 1.267 + D3D10_MAP mapType; 1.268 + 1.269 + if (aMapType == MapType::READ) { 1.270 + mapType = D3D10_MAP_READ; 1.271 + } else if (aMapType == MapType::WRITE) { 1.272 + mapType = D3D10_MAP_WRITE; 1.273 + } else { 1.274 + mapType = D3D10_MAP_READ_WRITE; 1.275 + } 1.276 + 1.277 + D3D10_MAPPED_TEXTURE2D map; 1.278 + 1.279 + HRESULT hr = mTexture->Map(0, mapType, 0, &map); 1.280 + 1.281 + if (FAILED(hr)) { 1.282 + gfxWarning() << "Texture map failed with code: " << hr; 1.283 + return false; 1.284 + } 1.285 + 1.286 + aMappedSurface->mData = (uint8_t*)map.pData; 1.287 + aMappedSurface->mStride = map.RowPitch; 1.288 + mIsMapped = true; 1.289 + 1.290 + return true; 1.291 +} 1.292 + 1.293 +void 1.294 +DataSourceSurfaceD2DTarget::Unmap() 1.295 +{ 1.296 + MOZ_ASSERT(mIsMapped); 1.297 + 1.298 + mIsMapped = false; 1.299 + mTexture->Unmap(0); 1.300 +} 1.301 + 1.302 +void 1.303 +DataSourceSurfaceD2DTarget::EnsureMapped() 1.304 +{ 1.305 + // Do not use GetData() after having used Map! 1.306 + MOZ_ASSERT(!mIsMapped); 1.307 + if (!mMapped) { 1.308 + HRESULT hr = mTexture->Map(0, D3D10_MAP_READ, 0, &mMap); 1.309 + if (FAILED(hr)) { 1.310 + gfxWarning() << "Failed to map texture to memory. Code: " << hr; 1.311 + return; 1.312 + } 1.313 + mMapped = true; 1.314 + } 1.315 +} 1.316 + 1.317 +} 1.318 +}