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()); }
internal void UpdateSubresource(GraphicsResource resource, int subResourceIndex, DataBox databox) { #if DEBUG GraphicsDevice.EnsureContextActive(); #endif var buffer = resource as Buffer; if (buffer != null) { #if SILICONSTUDIO_XENKO_GRAPHICS_API_OPENGLES if (buffer.StagingData != IntPtr.Zero) { // Specific case for constant buffers SiliconStudio.Core.Utilities.CopyMemory(buffer.StagingData, databox.DataPointer, buffer.Description.SizeInBytes); return; } #endif //UnbindVertexArrayObject(); if (!GraphicsDevice.HasTextureBuffers && buffer.BufferId == 0) { if (activeTexture != 0) { activeTexture = 0; GL.ActiveTexture(TextureUnit.Texture0); } // On platforms where it's not supported, we use a texture instead of a buffer GL.BindTexture(buffer.TextureTarget, buffer.TextureId); boundShaderResourceViews[0] = null; // bound active texture 0 has changed buffer.UpdateTextureSubresource(databox.DataPointer, 0, 0, buffer.ElementCount); } else { GL.BindBuffer(buffer.BufferTarget, buffer.BufferId); GL.BufferData(buffer.BufferTarget, buffer.Description.SizeInBytes, databox.DataPointer, buffer.BufferUsageHint); } } else { var texture = resource as Texture; if (texture != null) { if (activeTexture != 0) { activeTexture = 0; GL.ActiveTexture(TextureUnit.Texture0); } // TODO: Handle pitchs // TODO: handle other texture formats GL.BindTexture(texture.TextureTarget, texture.TextureId); boundShaderResourceViews[0] = null; // bound active texture 0 has changed var desc = texture.Description; var mipLevel = subResourceIndex % texture.MipLevels; var arraySlice = subResourceIndex / texture.MipLevels; switch (texture.TextureTarget) { #if !SILICONSTUDIO_XENKO_GRAPHICS_API_OPENGLES case TextureTarget.Texture1D: GL.TexSubImage1D(TextureTarget.Texture1D, mipLevel, 0, desc.Width, texture.TextureFormat, texture.TextureType, databox.DataPointer); break; #endif case TextureTarget.Texture2D: GL.TexSubImage2D(TextureTarget2d.Texture2D, mipLevel, 0, 0, desc.Width, desc.Height, texture.TextureFormat, texture.TextureType, databox.DataPointer); break; case TextureTarget.Texture2DArray: GL.TexSubImage3D(TextureTarget3d.Texture2DArray, mipLevel, 0, 0, arraySlice, desc.Width, desc.Height, 1, texture.TextureFormat, texture.TextureType, databox.DataPointer); break; case TextureTarget.Texture3D: GL.TexSubImage3D(TextureTarget3d.Texture3D, mipLevel, 0, 0, 0, desc.Width, desc.Height, desc.Depth, texture.TextureFormat, texture.TextureType, databox.DataPointer); break; case TextureTarget.TextureCubeMap: GL.TexSubImage2D(Texture.GetTextureTargetForDataSet2D(texture.TextureTarget, arraySlice), mipLevel, 0, 0, desc.Width, desc.Height, texture.TextureFormat, texture.TextureType, databox.DataPointer); break; default: Internal.Refactor.ThrowNotImplementedException("UpdateSubresource not implemented for texture target " + texture.TextureTarget); break; } } else // neither texture nor buffer { Internal.Refactor.ThrowNotImplementedException("UpdateSubresource not implemented for type " + resource.GetType()); } } }