2 // Copyright 2014 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.
7 // Buffer11.cpp Defines the Buffer11 class.
9 #include "libGLESv2/renderer/d3d/d3d11/Buffer11.h"
10 #include "libGLESv2/renderer/d3d/d3d11/Renderer11.h"
11 #include "libGLESv2/renderer/d3d/d3d11/formatutils11.h"
12 #include "libGLESv2/main.h"
17 PackPixelsParams::PackPixelsParams()
25 PackPixelsParams::PackPixelsParams(const gl::Rectangle &areaIn, GLenum formatIn, GLenum typeIn, GLuint outputPitchIn,
26 const gl::PixelPackState &packIn, ptrdiff_t offsetIn)
30 outputPitch(outputPitchIn),
31 packBuffer(packIn.pixelBuffer.get()),
32 pack(packIn.alignment, packIn.reverseRowOrder),
39 D3D11_MAP GetD3DMapTypeFromBits(GLbitfield access)
41 bool readBit = ((access & GL_MAP_READ_BIT) != 0);
42 bool writeBit = ((access & GL_MAP_WRITE_BIT) != 0);
44 ASSERT(readBit || writeBit);
46 // Note : we ignore the discard bit, because in D3D11, staging buffers
47 // don't accept the map-discard flag (discard only works for DYNAMIC usage)
49 if (readBit && !writeBit)
51 return D3D11_MAP_READ;
53 else if (writeBit && !readBit)
55 return D3D11_MAP_WRITE;
57 else if (writeBit && readBit)
59 return D3D11_MAP_READ_WRITE;
64 return D3D11_MAP_READ;
70 // Each instance of Buffer11::BufferStorage11 is specialized for a class of D3D binding points
71 // - vertex/transform feedback buffers
73 // - pixel unpack buffers
75 class Buffer11::BufferStorage11
78 virtual ~BufferStorage11() {}
80 DataRevision getDataRevision() const { return mRevision; }
81 BufferUsage getUsage() const { return mUsage; }
82 size_t getSize() const { return mBufferSize; }
83 bool isMappable() const { return (mUsage == BUFFER_USAGE_STAGING || mUsage == BUFFER_USAGE_PIXEL_PACK); }
85 void setDataRevision(DataRevision rev) { mRevision = rev; }
87 virtual bool copyFromStorage(BufferStorage11 *source, size_t sourceOffset,
88 size_t size, size_t destOffset) = 0;
89 virtual bool resize(size_t size, bool preserveData) = 0;
91 virtual void *map(size_t offset, size_t length, GLbitfield access) = 0;
92 virtual void unmap() = 0;
95 BufferStorage11(Renderer11 *renderer, BufferUsage usage);
97 Renderer11 *mRenderer;
98 DataRevision mRevision;
99 const BufferUsage mUsage;
103 // A native buffer storage represents an underlying D3D11 buffer for a particular
105 class Buffer11::NativeBuffer11 : public Buffer11::BufferStorage11
108 NativeBuffer11(Renderer11 *renderer, BufferUsage usage);
111 ID3D11Buffer *getNativeBuffer() const { return mNativeBuffer; }
113 virtual bool copyFromStorage(BufferStorage11 *source, size_t sourceOffset,
114 size_t size, size_t destOffset);
115 virtual bool resize(size_t size, bool preserveData);
117 virtual void *map(size_t offset, size_t length, GLbitfield access);
118 virtual void unmap();
120 bool setData(D3D11_MAP mapMode, const uint8_t *data, size_t size, size_t offset);
123 ID3D11Buffer *mNativeBuffer;
125 static void fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Renderer *renderer, BufferUsage usage, unsigned int bufferSize);
128 // Pack storage represents internal storage for pack buffers. We implement pack buffers
129 // as CPU memory, tied to a staging texture, for asynchronous texture readback.
130 class Buffer11::PackStorage11 : public Buffer11::BufferStorage11
133 PackStorage11(Renderer11 *renderer);
136 virtual bool copyFromStorage(BufferStorage11 *source, size_t sourceOffset,
137 size_t size, size_t destOffset);
138 virtual bool resize(size_t size, bool preserveData);
140 virtual void *map(size_t offset, size_t length, GLbitfield access);
141 virtual void unmap();
143 gl::Error packPixels(ID3D11Texture2D *srcTexure, UINT srcSubresource, const PackPixelsParams ¶ms);
147 void flushQueuedPackCommand();
149 ID3D11Texture2D *mStagingTexture;
150 DXGI_FORMAT mTextureFormat;
151 gl::Extents mTextureSize;
152 MemoryBuffer mMemoryBuffer;
153 PackPixelsParams *mQueuedPackCommand;
154 PackPixelsParams mPackParams;
159 Buffer11::Buffer11(Renderer11 *renderer)
163 mMappedStorage(NULL),
164 mResolvedDataRevision(0),
168 Buffer11::~Buffer11()
170 for (auto it = mBufferStorages.begin(); it != mBufferStorages.end(); it++)
172 SafeDelete(it->second);
176 Buffer11 *Buffer11::makeBuffer11(BufferImpl *buffer)
178 ASSERT(HAS_DYNAMIC_TYPE(Buffer11*, buffer));
179 return static_cast<Buffer11*>(buffer);
182 gl::Error Buffer11::setData(const void *data, size_t size, GLenum usage)
184 gl::Error error = setSubData(data, size, 0);
190 if (usage == GL_STATIC_DRAW)
192 initializeStaticData();
198 void *Buffer11::getData()
200 NativeBuffer11 *stagingBuffer = getStagingBuffer();
208 if (stagingBuffer->getDataRevision() > mResolvedDataRevision)
210 if (stagingBuffer->getSize() > mResolvedData.size())
212 if (!mResolvedData.resize(stagingBuffer->getSize()))
214 return gl::error(GL_OUT_OF_MEMORY, (void*)NULL);
218 ID3D11DeviceContext *context = mRenderer->getDeviceContext();
220 D3D11_MAPPED_SUBRESOURCE mappedResource;
221 HRESULT result = context->Map(stagingBuffer->getNativeBuffer(), 0, D3D11_MAP_READ, 0, &mappedResource);
224 return gl::error(GL_OUT_OF_MEMORY, (void*)NULL);
227 memcpy(mResolvedData.data(), mappedResource.pData, stagingBuffer->getSize());
229 context->Unmap(stagingBuffer->getNativeBuffer(), 0);
231 mResolvedDataRevision = stagingBuffer->getDataRevision();
236 // Only happens if we initialized the buffer with no data (NULL)
237 if (mResolvedData.empty())
239 if (!mResolvedData.resize(mSize))
241 return gl::error(GL_OUT_OF_MEMORY, (void*)NULL);
245 ASSERT(mResolvedData.size() >= mSize);
247 return mResolvedData.data();
250 gl::Error Buffer11::setSubData(const void *data, size_t size, size_t offset)
252 size_t requiredSize = size + offset;
254 if (data && size > 0)
256 NativeBuffer11 *stagingBuffer = getStagingBuffer();
260 return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal staging buffer.");
263 // Explicitly resize the staging buffer, preserving data if the new data will not
264 // completely fill the buffer
265 if (stagingBuffer->getSize() < requiredSize)
267 bool preserveData = (offset > 0);
268 if (!stagingBuffer->resize(requiredSize, preserveData))
270 return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize internal staging buffer.");
274 if (!stagingBuffer->setData(D3D11_MAP_WRITE, reinterpret_cast<const uint8_t *>(data), size, offset))
276 return gl::Error(GL_OUT_OF_MEMORY, "Failed to set data on internal staging buffer.");
279 stagingBuffer->setDataRevision(stagingBuffer->getDataRevision() + 1);
282 mSize = std::max(mSize, requiredSize);
283 invalidateStaticData();
285 return gl::Error(GL_NO_ERROR);
288 gl::Error Buffer11::copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size)
290 Buffer11 *sourceBuffer = makeBuffer11(source);
291 ASSERT(sourceBuffer != NULL);
293 BufferStorage11 *copyDest = getLatestBufferStorage();
296 copyDest = getStagingBuffer();
299 BufferStorage11 *copySource = sourceBuffer->getLatestBufferStorage();
301 if (!copySource || !copyDest)
303 return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal staging buffer.");
306 // If copying to/from a pixel pack buffer, we must have a staging or
307 // pack buffer partner, because other native buffers can't be mapped
308 if (copyDest->getUsage() == BUFFER_USAGE_PIXEL_PACK && !copySource->isMappable())
310 copySource = sourceBuffer->getStagingBuffer();
312 else if (copySource->getUsage() == BUFFER_USAGE_PIXEL_PACK && !copyDest->isMappable())
314 copyDest = getStagingBuffer();
317 // D3D11 does not allow overlapped copies until 11.1, and only if the
318 // device supports D3D11_FEATURE_DATA_D3D11_OPTIONS::CopyWithOverlap
319 // Get around this via a different source buffer
320 if (copySource == copyDest)
322 if (copySource->getUsage() == BUFFER_USAGE_STAGING)
324 copySource = getBufferStorage(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK);
328 copySource = getStagingBuffer();
332 copyDest->copyFromStorage(copySource, sourceOffset, size, destOffset);
333 copyDest->setDataRevision(copyDest->getDataRevision() + 1);
335 mSize = std::max<size_t>(mSize, destOffset + size);
336 invalidateStaticData();
338 return gl::Error(GL_NO_ERROR);
341 gl::Error Buffer11::map(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr)
343 ASSERT(!mMappedStorage);
345 BufferStorage11 *latestStorage = getLatestBufferStorage();
347 (latestStorage->getUsage() == BUFFER_USAGE_PIXEL_PACK ||
348 latestStorage->getUsage() == BUFFER_USAGE_STAGING))
350 // Latest storage is mappable.
351 mMappedStorage = latestStorage;
355 // Fall back to using the staging buffer if the latest storage does
356 // not exist or is not CPU-accessible.
357 mMappedStorage = getStagingBuffer();
362 return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate mappable internal buffer.");
365 if ((access & GL_MAP_WRITE_BIT) > 0)
367 // Update the data revision immediately, since the data might be changed at any time
368 mMappedStorage->setDataRevision(mMappedStorage->getDataRevision() + 1);
371 void *mappedBuffer = mMappedStorage->map(offset, length, access);
374 return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal buffer.");
377 *mapPtr = mappedBuffer;
378 return gl::Error(GL_NO_ERROR);
381 gl::Error Buffer11::unmap()
383 ASSERT(mMappedStorage);
384 mMappedStorage->unmap();
385 mMappedStorage = NULL;
386 return gl::Error(GL_NO_ERROR);
389 void Buffer11::markTransformFeedbackUsage()
391 BufferStorage11 *transformFeedbackStorage = getBufferStorage(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK);
393 if (transformFeedbackStorage)
395 transformFeedbackStorage->setDataRevision(transformFeedbackStorage->getDataRevision() + 1);
398 invalidateStaticData();
401 void Buffer11::markBufferUsage()
405 const unsigned int usageLimit = 5;
407 if (mReadUsageCount > usageLimit && mResolvedData.size() > 0)
409 mResolvedData.resize(0);
410 mResolvedDataRevision = 0;
414 Renderer* Buffer11::getRenderer()
419 ID3D11Buffer *Buffer11::getBuffer(BufferUsage usage)
423 BufferStorage11 *bufferStorage = getBufferStorage(usage);
427 // Storage out-of-memory
431 ASSERT(HAS_DYNAMIC_TYPE(NativeBuffer11*, bufferStorage));
433 return static_cast<NativeBuffer11*>(bufferStorage)->getNativeBuffer();
436 ID3D11ShaderResourceView *Buffer11::getSRV(DXGI_FORMAT srvFormat)
438 BufferStorage11 *storage = getBufferStorage(BUFFER_USAGE_PIXEL_UNPACK);
442 // Storage out-of-memory
446 ASSERT(HAS_DYNAMIC_TYPE(NativeBuffer11*, storage));
447 ID3D11Buffer *buffer = static_cast<NativeBuffer11*>(storage)->getNativeBuffer();
449 auto bufferSRVIt = mBufferResourceViews.find(srvFormat);
451 if (bufferSRVIt != mBufferResourceViews.end())
453 if (bufferSRVIt->second.first == buffer)
455 return bufferSRVIt->second.second;
459 // The underlying buffer has changed since the SRV was created: recreate the SRV.
460 SafeRelease(bufferSRVIt->second.second);
464 ID3D11Device *device = mRenderer->getDevice();
465 ID3D11ShaderResourceView *bufferSRV = NULL;
467 const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(srvFormat);
469 D3D11_SHADER_RESOURCE_VIEW_DESC bufferSRVDesc;
470 bufferSRVDesc.Buffer.ElementOffset = 0;
471 bufferSRVDesc.Buffer.ElementWidth = mSize / dxgiFormatInfo.pixelBytes;
472 bufferSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
473 bufferSRVDesc.Format = srvFormat;
475 HRESULT result = device->CreateShaderResourceView(buffer, &bufferSRVDesc, &bufferSRV);
476 UNUSED_ASSERTION_VARIABLE(result);
477 ASSERT(SUCCEEDED(result));
479 mBufferResourceViews[srvFormat] = BufferSRVPair(buffer, bufferSRV);
484 gl::Error Buffer11::packPixels(ID3D11Texture2D *srcTexture, UINT srcSubresource, const PackPixelsParams ¶ms)
486 PackStorage11 *packStorage = getPackStorage();
488 BufferStorage11 *latestStorage = getLatestBufferStorage();
492 gl::Error error = packStorage->packPixels(srcTexture, srcSubresource, params);
497 packStorage->setDataRevision(latestStorage ? latestStorage->getDataRevision() + 1 : 1);
500 return gl::Error(GL_NO_ERROR);
503 Buffer11::BufferStorage11 *Buffer11::getBufferStorage(BufferUsage usage)
505 BufferStorage11 *directBuffer = NULL;
506 auto directBufferIt = mBufferStorages.find(usage);
507 if (directBufferIt != mBufferStorages.end())
509 directBuffer = directBufferIt->second;
514 if (usage == BUFFER_USAGE_PIXEL_PACK)
516 directBuffer = new PackStorage11(mRenderer);
520 // buffer is not allocated, create it
521 directBuffer = new NativeBuffer11(mRenderer, usage);
524 mBufferStorages.insert(std::make_pair(usage, directBuffer));
528 if (directBuffer->getSize() < mSize)
530 if (!directBuffer->resize(mSize, true))
532 // Out of memory error
537 BufferStorage11 *latestBuffer = getLatestBufferStorage();
538 if (latestBuffer && latestBuffer->getDataRevision() > directBuffer->getDataRevision())
540 // if copying from a pack buffer to a non-staging native buffer, we must first
541 // copy through the staging buffer, because other native buffers can't be mapped
542 if (latestBuffer->getUsage() == BUFFER_USAGE_PIXEL_PACK && !directBuffer->isMappable())
544 NativeBuffer11 *stagingBuffer = getStagingBuffer();
546 stagingBuffer->copyFromStorage(latestBuffer, 0, latestBuffer->getSize(), 0);
547 directBuffer->setDataRevision(latestBuffer->getDataRevision());
549 latestBuffer = stagingBuffer;
552 // if copyFromStorage returns true, the D3D buffer has been recreated
553 // and we should update our serial
554 if (directBuffer->copyFromStorage(latestBuffer, 0, latestBuffer->getSize(), 0))
558 directBuffer->setDataRevision(latestBuffer->getDataRevision());
564 Buffer11::BufferStorage11 *Buffer11::getLatestBufferStorage() const
566 // Even though we iterate over all the direct buffers, it is expected that only
567 // 1 or 2 will be present.
568 BufferStorage11 *latestStorage = NULL;
569 DataRevision latestRevision = 0;
570 for (auto it = mBufferStorages.begin(); it != mBufferStorages.end(); it++)
572 BufferStorage11 *storage = it->second;
573 if (!latestStorage || storage->getDataRevision() > latestRevision)
575 latestStorage = storage;
576 latestRevision = storage->getDataRevision();
580 return latestStorage;
583 Buffer11::NativeBuffer11 *Buffer11::getStagingBuffer()
585 BufferStorage11 *stagingStorage = getBufferStorage(BUFFER_USAGE_STAGING);
593 ASSERT(HAS_DYNAMIC_TYPE(NativeBuffer11*, stagingStorage));
594 return static_cast<NativeBuffer11*>(stagingStorage);
597 Buffer11::PackStorage11 *Buffer11::getPackStorage()
599 BufferStorage11 *packStorage = getBufferStorage(BUFFER_USAGE_PIXEL_PACK);
607 ASSERT(HAS_DYNAMIC_TYPE(PackStorage11*, packStorage));
608 return static_cast<PackStorage11*>(packStorage);
611 bool Buffer11::supportsDirectBinding() const
613 // Do not support direct buffers for dynamic data. The streaming buffer
614 // offers better performance for data which changes every frame.
615 // Check for absence of static buffer interfaces to detect dynamic data.
616 return (mStaticVertexBuffer && mStaticIndexBuffer);
619 Buffer11::BufferStorage11::BufferStorage11(Renderer11 *renderer, BufferUsage usage)
620 : mRenderer(renderer),
627 Buffer11::NativeBuffer11::NativeBuffer11(Renderer11 *renderer, BufferUsage usage)
628 : BufferStorage11(renderer, usage),
633 Buffer11::NativeBuffer11::~NativeBuffer11()
635 SafeRelease(mNativeBuffer);
638 // Returns true if it recreates the direct buffer
639 bool Buffer11::NativeBuffer11::copyFromStorage(BufferStorage11 *source, size_t sourceOffset,
640 size_t size, size_t destOffset)
642 ID3D11DeviceContext *context = mRenderer->getDeviceContext();
644 size_t requiredSize = sourceOffset + size;
645 bool createBuffer = !mNativeBuffer || mBufferSize < requiredSize;
647 // (Re)initialize D3D buffer if needed
650 bool preserveData = (destOffset > 0);
651 resize(source->getSize(), preserveData);
654 if (source->getUsage() == BUFFER_USAGE_PIXEL_PACK)
656 ASSERT(HAS_DYNAMIC_TYPE(PackStorage11*, source));
658 void *sourcePointer = source->map(sourceOffset, size, GL_MAP_READ_BIT);
660 D3D11_MAPPED_SUBRESOURCE mappedResource;
661 HRESULT hr = context->Map(mNativeBuffer, 0, D3D11_MAP_WRITE, 0, &mappedResource);
662 UNUSED_ASSERTION_VARIABLE(hr);
663 ASSERT(SUCCEEDED(hr));
665 unsigned char *destPointer = static_cast<unsigned char *>(mappedResource.pData) + destOffset;
667 // Offset bounds are validated at the API layer
668 ASSERT(sourceOffset + size <= destOffset + mBufferSize);
669 memcpy(destPointer, sourcePointer, size);
673 ASSERT(HAS_DYNAMIC_TYPE(NativeBuffer11*, source));
676 srcBox.left = sourceOffset;
677 srcBox.right = sourceOffset + size;
683 ASSERT(HAS_DYNAMIC_TYPE(NativeBuffer11*, source));
684 ID3D11Buffer *sourceBuffer = static_cast<NativeBuffer11*>(source)->getNativeBuffer();
686 context->CopySubresourceRegion(mNativeBuffer, 0, destOffset, 0, 0, sourceBuffer, 0, &srcBox);
692 bool Buffer11::NativeBuffer11::resize(size_t size, bool preserveData)
694 ID3D11Device *device = mRenderer->getDevice();
695 ID3D11DeviceContext *context = mRenderer->getDeviceContext();
697 D3D11_BUFFER_DESC bufferDesc;
698 fillBufferDesc(&bufferDesc, mRenderer, mUsage, size);
700 ID3D11Buffer *newBuffer;
701 HRESULT result = device->CreateBuffer(&bufferDesc, NULL, &newBuffer);
705 return gl::error(GL_OUT_OF_MEMORY, false);
708 if (mNativeBuffer && preserveData)
710 // We don't call resize if the buffer is big enough already.
711 ASSERT(mBufferSize <= size);
715 srcBox.right = mBufferSize;
721 context->CopySubresourceRegion(newBuffer, 0, 0, 0, 0, mNativeBuffer, 0, &srcBox);
724 // No longer need the old buffer
725 SafeRelease(mNativeBuffer);
726 mNativeBuffer = newBuffer;
728 mBufferSize = bufferDesc.ByteWidth;
733 void Buffer11::NativeBuffer11::fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Renderer *renderer,
734 BufferUsage usage, unsigned int bufferSize)
736 bufferDesc->ByteWidth = bufferSize;
737 bufferDesc->MiscFlags = 0;
738 bufferDesc->StructureByteStride = 0;
742 case BUFFER_USAGE_STAGING:
743 bufferDesc->Usage = D3D11_USAGE_STAGING;
744 bufferDesc->BindFlags = 0;
745 bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
748 case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK:
749 bufferDesc->Usage = D3D11_USAGE_DEFAULT;
750 bufferDesc->BindFlags = D3D11_BIND_VERTEX_BUFFER | D3D11_BIND_STREAM_OUTPUT;
751 bufferDesc->CPUAccessFlags = 0;
754 case BUFFER_USAGE_INDEX:
755 bufferDesc->Usage = D3D11_USAGE_DEFAULT;
756 bufferDesc->BindFlags = D3D11_BIND_INDEX_BUFFER;
757 bufferDesc->CPUAccessFlags = 0;
760 case BUFFER_USAGE_PIXEL_UNPACK:
761 bufferDesc->Usage = D3D11_USAGE_DEFAULT;
762 bufferDesc->BindFlags = D3D11_BIND_SHADER_RESOURCE;
763 bufferDesc->CPUAccessFlags = 0;
766 case BUFFER_USAGE_UNIFORM:
767 bufferDesc->Usage = D3D11_USAGE_DYNAMIC;
768 bufferDesc->BindFlags = D3D11_BIND_CONSTANT_BUFFER;
769 bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
771 // Constant buffers must be of a limited size, and aligned to 16 byte boundaries
772 // For our purposes we ignore any buffer data past the maximum constant buffer size
773 bufferDesc->ByteWidth = roundUp(bufferDesc->ByteWidth, 16u);
774 bufferDesc->ByteWidth = std::min<UINT>(bufferDesc->ByteWidth, renderer->getRendererCaps().maxUniformBlockSize);
782 void *Buffer11::NativeBuffer11::map(size_t offset, size_t length, GLbitfield access)
784 ASSERT(mUsage == BUFFER_USAGE_STAGING);
786 D3D11_MAPPED_SUBRESOURCE mappedResource;
787 ID3D11DeviceContext *context = mRenderer->getDeviceContext();
788 D3D11_MAP d3dMapType = gl_d3d11::GetD3DMapTypeFromBits(access);
789 UINT d3dMapFlag = ((access & GL_MAP_UNSYNCHRONIZED_BIT) != 0 ? D3D11_MAP_FLAG_DO_NOT_WAIT : 0);
791 HRESULT result = context->Map(mNativeBuffer, 0, d3dMapType, d3dMapFlag, &mappedResource);
792 UNUSED_ASSERTION_VARIABLE(result);
793 ASSERT(SUCCEEDED(result));
795 return static_cast<GLubyte*>(mappedResource.pData) + offset;
798 bool Buffer11::NativeBuffer11::setData(D3D11_MAP mapMode, const uint8_t *data, size_t size, size_t offset)
800 ID3D11DeviceContext *context = mRenderer->getDeviceContext();
802 D3D11_MAPPED_SUBRESOURCE mappedResource;
803 HRESULT result = context->Map(mNativeBuffer, 0, mapMode, 0, &mappedResource);
806 return gl::error(GL_OUT_OF_MEMORY, false);
809 uint8_t *offsetBufferPointer = reinterpret_cast<uint8_t *>(mappedResource.pData) + offset;
810 memcpy(offsetBufferPointer, data, size);
812 context->Unmap(mNativeBuffer, 0);
817 void Buffer11::NativeBuffer11::unmap()
819 ASSERT(mUsage == BUFFER_USAGE_STAGING);
820 ID3D11DeviceContext *context = mRenderer->getDeviceContext();
821 context->Unmap(mNativeBuffer, 0);
824 Buffer11::PackStorage11::PackStorage11(Renderer11 *renderer)
825 : BufferStorage11(renderer, BUFFER_USAGE_PIXEL_PACK),
826 mStagingTexture(NULL),
827 mTextureFormat(DXGI_FORMAT_UNKNOWN),
828 mQueuedPackCommand(NULL),
833 Buffer11::PackStorage11::~PackStorage11()
835 SafeRelease(mStagingTexture);
836 SafeDelete(mQueuedPackCommand);
839 bool Buffer11::PackStorage11::copyFromStorage(BufferStorage11 *source, size_t sourceOffset,
840 size_t size, size_t destOffset)
842 // We copy through a staging buffer when drawing with a pack buffer,
843 // or for other cases where we access the pack buffer
848 bool Buffer11::PackStorage11::resize(size_t size, bool preserveData)
850 if (size != mBufferSize)
852 if (!mMemoryBuffer.resize(size))
862 void *Buffer11::PackStorage11::map(size_t offset, size_t length, GLbitfield access)
864 ASSERT(offset + length <= getSize());
866 // We might be able to optimize out one or more memcpy calls by detecting when
867 // and if D3D packs the staging texture memory identically to how we would fill
868 // the pack buffer according to the current pack state.
870 flushQueuedPackCommand();
871 mDataModified = (mDataModified || (access & GL_MAP_WRITE_BIT) != 0);
873 return mMemoryBuffer.data() + offset;
876 void Buffer11::PackStorage11::unmap()
881 gl::Error Buffer11::PackStorage11::packPixels(ID3D11Texture2D *srcTexure, UINT srcSubresource, const PackPixelsParams ¶ms)
883 flushQueuedPackCommand();
884 mQueuedPackCommand = new PackPixelsParams(params);
886 D3D11_TEXTURE2D_DESC textureDesc;
887 srcTexure->GetDesc(&textureDesc);
889 if (mStagingTexture != NULL &&
890 (mTextureFormat != textureDesc.Format ||
891 mTextureSize.width != params.area.width ||
892 mTextureSize.height != params.area.height))
894 SafeRelease(mStagingTexture);
895 mTextureSize.width = 0;
896 mTextureSize.height = 0;
897 mTextureFormat = DXGI_FORMAT_UNKNOWN;
900 if (mStagingTexture == NULL)
902 ID3D11Device *device = mRenderer->getDevice();
905 mTextureSize.width = params.area.width;
906 mTextureSize.height = params.area.height;
907 mTextureFormat = textureDesc.Format;
909 D3D11_TEXTURE2D_DESC stagingDesc;
910 stagingDesc.Width = params.area.width;
911 stagingDesc.Height = params.area.height;
912 stagingDesc.MipLevels = 1;
913 stagingDesc.ArraySize = 1;
914 stagingDesc.Format = mTextureFormat;
915 stagingDesc.SampleDesc.Count = 1;
916 stagingDesc.SampleDesc.Quality = 0;
917 stagingDesc.Usage = D3D11_USAGE_STAGING;
918 stagingDesc.BindFlags = 0;
919 stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
920 stagingDesc.MiscFlags = 0;
922 hr = device->CreateTexture2D(&stagingDesc, NULL, &mStagingTexture);
925 ASSERT(hr == E_OUTOFMEMORY);
926 return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal staging texture.");
930 // ReadPixels from multisampled FBOs isn't supported in current GL
931 ASSERT(textureDesc.SampleDesc.Count <= 1);
933 ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext();
935 srcBox.left = params.area.x;
936 srcBox.right = params.area.x + params.area.width;
937 srcBox.top = params.area.y;
938 srcBox.bottom = params.area.y + params.area.height;
943 immediateContext->CopySubresourceRegion(mStagingTexture, 0, 0, 0, 0, srcTexure, srcSubresource, &srcBox);
945 return gl::Error(GL_NO_ERROR);
948 void Buffer11::PackStorage11::flushQueuedPackCommand()
950 ASSERT(mMemoryBuffer.size() > 0);
952 if (mQueuedPackCommand)
954 mRenderer->packPixels(mStagingTexture, *mQueuedPackCommand, mMemoryBuffer.data());
955 SafeDelete(mQueuedPackCommand);