public MappedResource MapSubresource(GraphicsResource resource, int subResourceIndex, MapMode mapMode, bool doNotWait = false, int offsetInBytes = 0, int lengthInBytes = 0) { #if DEBUG GraphicsDevice.EnsureContextActive(); #endif // This resource has just been recycled by the GraphicsResourceAllocator, we force a rename to avoid GPU=>GPU sync point if (resource.DiscardNextMap && mapMode == MapMode.WriteNoOverwrite) mapMode = MapMode.WriteDiscard; var buffer = resource as Buffer; if (buffer != null) { if (lengthInBytes == 0) lengthInBytes = buffer.Description.SizeInBytes; if (buffer.StagingData != IntPtr.Zero) { // Specific case for constant buffers return new MappedResource(resource, subResourceIndex, new DataBox { DataPointer = buffer.StagingData + offsetInBytes, SlicePitch = 0, RowPitch = 0 }, offsetInBytes, lengthInBytes); } #if SILICONSTUDIO_XENKO_GRAPHICS_API_OPENGLES // OpenGL ES 2 needs Staging Data if (GraphicsDevice.IsOpenGLES2) { Internal.Refactor.ThrowNotImplementedException(); } #endif IntPtr mapResult = IntPtr.Zero; //UnbindVertexArrayObject(); GL.BindBuffer(buffer.BufferTarget, buffer.BufferId); #if !SILICONSTUDIO_XENKO_GRAPHICS_API_OPENGLES //if (mapMode != MapMode.WriteDiscard && mapMode != MapMode.WriteNoOverwrite) // mapResult = GL.MapBuffer(buffer.bufferTarget, mapMode.ToOpenGL()); //else #endif { // Orphan the buffer (let driver knows we don't need it anymore) if (mapMode == MapMode.WriteDiscard) { doNotWait = true; GL.BufferData(buffer.BufferTarget, (IntPtr)buffer.Description.SizeInBytes, IntPtr.Zero, buffer.BufferUsageHint); } var unsynchronized = doNotWait && mapMode != MapMode.Read && mapMode != MapMode.ReadWrite; mapResult = GL.MapBufferRange(buffer.BufferTarget, (IntPtr)offsetInBytes, (IntPtr)lengthInBytes, mapMode.ToOpenGLMask() | (unsynchronized ? BufferAccessMask.MapUnsynchronizedBit : 0)); } return new MappedResource(resource, subResourceIndex, new DataBox { DataPointer = mapResult, SlicePitch = 0, RowPitch = 0 }); } var texture = resource as Texture; if (texture != null) { if (lengthInBytes == 0) lengthInBytes = texture.ComputeSubresourceSize(subResourceIndex); if (mapMode == MapMode.Read) { if (texture.Description.Usage != GraphicsResourceUsage.Staging) throw new NotSupportedException("Only staging textures can be mapped."); var mipLevel = subResourceIndex % texture.MipLevels; #if SILICONSTUDIO_XENKO_GRAPHICS_API_OPENGLES if (GraphicsDevice.IsOpenGLES2 || texture.StagingData != IntPtr.Zero) { return new MappedResource(resource, subResourceIndex, new DataBox { DataPointer = texture.StagingData + offsetInBytes + texture.ComputeBufferOffset(subResourceIndex, 0), SlicePitch = texture.ComputeSlicePitch(mipLevel), RowPitch = texture.ComputeRowPitch(mipLevel) }, offsetInBytes, lengthInBytes); } else #endif { if (doNotWait) { // Wait at least 2 frames after last operation if (GraphicsDevice.FrameCounter < texture.PixelBufferFrame + ReadbackFrameDelay) { return new MappedResource(resource, subResourceIndex, new DataBox(), offsetInBytes, lengthInBytes); } } return MapTexture(texture, true, BufferTarget.PixelPackBuffer, texture.PixelBufferObjectId, subResourceIndex, mapMode, offsetInBytes, lengthInBytes); } } else if (mapMode == MapMode.WriteDiscard) { #if SILICONSTUDIO_XENKO_GRAPHICS_API_OPENGLES if (GraphicsDevice.IsOpenGLES2) { Internal.Refactor.ThrowNotImplementedException(); } #endif if (texture.Description.Usage != GraphicsResourceUsage.Dynamic) throw new NotSupportedException("Only dynamic texture can be mapped."); // Create a temporary unpack pixel buffer // TODO: Pool/allocator? (it's an upload buffer basically) var pixelBufferObjectId = texture.GeneratePixelBufferObject(BufferTarget.PixelUnpackBuffer, PixelStoreParameter.UnpackAlignment, BufferUsageHint.DynamicCopy, texture.ComputeSubresourceSize(subResourceIndex)); return MapTexture(texture, false, BufferTarget.PixelUnpackBuffer, pixelBufferObjectId, subResourceIndex, mapMode, offsetInBytes, lengthInBytes); } } throw Internal.Refactor.NewNotImplementedException("MapSubresource not implemented for type " + resource.GetType()); }
private MappedResource MapTexture(Texture texture, bool adjustOffsetForSubresource, BufferTarget bufferTarget, int pixelBufferObjectId, int subResourceIndex, MapMode mapMode, int offsetInBytes, int lengthInBytes) { int mipLevel = subResourceIndex % texture.MipLevels; GL.BindBuffer(bufferTarget, pixelBufferObjectId); var mapResult = GL.MapBufferRange(bufferTarget, (IntPtr)offsetInBytes + (adjustOffsetForSubresource ? texture.ComputeBufferOffset(subResourceIndex, 0) : 0), (IntPtr)lengthInBytes, mapMode.ToOpenGLMask()); GL.BindBuffer(bufferTarget, 0); return new MappedResource(texture, subResourceIndex, new DataBox { DataPointer = mapResult, SlicePitch = texture.ComputeSlicePitch(mipLevel), RowPitch = texture.ComputeRowPitch(mipLevel) }, offsetInBytes, lengthInBytes) { PixelBufferObjectId = pixelBufferObjectId, }; }