Bug 1940374 - Readback snapshot when last submitted TextureId is valid r=gfx-reviewers,lsalzman
Store last submitted TextureId in PresentationData for getting front buffer snapshot. WebGPUParent::RecvQueueSubmit() stores the latest TextureId in the swap chain in PresentationData::LastSubmittedTextureId. To do so, it retrieves the OwnerId from ExternalTexture. Next, get PresentationData from OwnerId. If readback is required, it is performed synchronously. Its implementation is borrowed from WebGPUParent::RecvSwapChainPresent(). Differential Revision: https://phabricator.services.mozilla.com/D233473
This commit is contained in:
@@ -331,7 +331,7 @@ NS_IMETHODIMP CanvasContext::GetInputStream(const char* aMimeType,
|
|||||||
aMimeType, aEncoderOptions, aStream);
|
aMimeType, aEncoderOptions, aStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<mozilla::gfx::SourceSurface> CanvasContext::GetSurfaceSnapshot(
|
already_AddRefed<gfx::SourceSurface> CanvasContext::GetSurfaceSnapshot(
|
||||||
gfxAlphaType* aOutAlphaType) {
|
gfxAlphaType* aOutAlphaType) {
|
||||||
if (aOutAlphaType) {
|
if (aOutAlphaType) {
|
||||||
*aOutAlphaType = gfxAlphaType::Premult;
|
*aOutAlphaType = gfxAlphaType::Premult;
|
||||||
@@ -347,9 +347,16 @@ already_AddRefed<mozilla::gfx::SourceSurface> CanvasContext::GetSurfaceSnapshot(
|
|||||||
}
|
}
|
||||||
|
|
||||||
MOZ_ASSERT(mRemoteTextureOwnerId.isSome());
|
MOZ_ASSERT(mRemoteTextureOwnerId.isSome());
|
||||||
return cm->GetSnapshot(cm->Id(), mBridge->Id(), mRemoteTextureOwnerId,
|
|
||||||
mGfxFormat, /* aPremultiply */ false,
|
// The parent side needs to create a command encoder which will be submitted
|
||||||
/* aYFlip */ false);
|
// and dropped right away so we create and release an encoder ID here.
|
||||||
|
RawId encoderId = ffi::wgpu_client_make_encoder_id(mBridge->GetClient());
|
||||||
|
RefPtr<gfx::SourceSurface> snapshot =
|
||||||
|
cm->GetSnapshot(cm->Id(), mBridge->Id(), mRemoteTextureOwnerId,
|
||||||
|
Some(encoderId), mGfxFormat, /* aPremultiply */ false,
|
||||||
|
/* aYFlip */ false);
|
||||||
|
ffi::wgpu_client_free_command_encoder_id(mBridge->GetClient(), encoderId);
|
||||||
|
return snapshot.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
Maybe<layers::SurfaceDescriptor> CanvasContext::GetFrontBuffer(
|
Maybe<layers::SurfaceDescriptor> CanvasContext::GetFrontBuffer(
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ class CanvasContext final : public nsICanvasRenderingContextInternal,
|
|||||||
NS_IMETHOD GetInputStream(const char* aMimeType,
|
NS_IMETHOD GetInputStream(const char* aMimeType,
|
||||||
const nsAString& aEncoderOptions,
|
const nsAString& aEncoderOptions,
|
||||||
nsIInputStream** aStream) override;
|
nsIInputStream** aStream) override;
|
||||||
already_AddRefed<mozilla::gfx::SourceSurface> GetSurfaceSnapshot(
|
already_AddRefed<gfx::SourceSurface> GetSurfaceSnapshot(
|
||||||
gfxAlphaType* aOutAlphaType) override;
|
gfxAlphaType* aOutAlphaType) override;
|
||||||
|
|
||||||
void SetOpaqueValueFromOpaqueAttr(bool aOpaqueAttrValue) override {}
|
void SetOpaqueValueFromOpaqueAttr(bool aOpaqueAttrValue) override {}
|
||||||
|
|||||||
@@ -55,4 +55,21 @@ void ExternalTexture::SetSubmissionIndex(uint64_t aSubmissionIndex) {
|
|||||||
mSubmissionIndex = aSubmissionIndex;
|
mSubmissionIndex = aSubmissionIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UniquePtr<ExternalTextureReadBackPresent>
|
||||||
|
ExternalTextureReadBackPresent::Create(
|
||||||
|
const uint32_t aWidth, const uint32_t aHeight,
|
||||||
|
const struct ffi::WGPUTextureFormat aFormat,
|
||||||
|
const ffi::WGPUTextureUsages aUsage) {
|
||||||
|
return MakeUnique<ExternalTextureReadBackPresent>(aWidth, aHeight, aFormat,
|
||||||
|
aUsage);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExternalTextureReadBackPresent::ExternalTextureReadBackPresent(
|
||||||
|
const uint32_t aWidth, const uint32_t aHeight,
|
||||||
|
const struct ffi::WGPUTextureFormat aFormat,
|
||||||
|
const ffi::WGPUTextureUsages aUsage)
|
||||||
|
: ExternalTexture(aWidth, aHeight, aFormat, aUsage) {}
|
||||||
|
|
||||||
|
ExternalTextureReadBackPresent::~ExternalTextureReadBackPresent() {}
|
||||||
|
|
||||||
} // namespace mozilla::webgpu
|
} // namespace mozilla::webgpu
|
||||||
|
|||||||
@@ -57,6 +57,14 @@ class ExternalTexture {
|
|||||||
void SetSubmissionIndex(uint64_t aSubmissionIndex);
|
void SetSubmissionIndex(uint64_t aSubmissionIndex);
|
||||||
uint64_t GetSubmissionIndex() const { return mSubmissionIndex; }
|
uint64_t GetSubmissionIndex() const { return mSubmissionIndex; }
|
||||||
|
|
||||||
|
void SetOwnerId(const layers::RemoteTextureOwnerId aOwnerId) {
|
||||||
|
mOwnerId = aOwnerId;
|
||||||
|
}
|
||||||
|
layers::RemoteTextureOwnerId GetOwnerId() const {
|
||||||
|
MOZ_ASSERT(mOwnerId.IsValid());
|
||||||
|
return mOwnerId;
|
||||||
|
}
|
||||||
|
|
||||||
const uint32_t mWidth;
|
const uint32_t mWidth;
|
||||||
const uint32_t mHeight;
|
const uint32_t mHeight;
|
||||||
const struct ffi::WGPUTextureFormat mFormat;
|
const struct ffi::WGPUTextureFormat mFormat;
|
||||||
@@ -64,6 +72,26 @@ class ExternalTexture {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
uint64_t mSubmissionIndex = 0;
|
uint64_t mSubmissionIndex = 0;
|
||||||
|
layers::RemoteTextureOwnerId mOwnerId;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Dummy class
|
||||||
|
class ExternalTextureReadBackPresent final : public ExternalTexture {
|
||||||
|
public:
|
||||||
|
static UniquePtr<ExternalTextureReadBackPresent> Create(
|
||||||
|
const uint32_t aWidth, const uint32_t aHeight,
|
||||||
|
const struct ffi::WGPUTextureFormat aFormat,
|
||||||
|
const ffi::WGPUTextureUsages aUsage);
|
||||||
|
|
||||||
|
ExternalTextureReadBackPresent(const uint32_t aWidth, const uint32_t aHeight,
|
||||||
|
const struct ffi::WGPUTextureFormat aFormat,
|
||||||
|
const ffi::WGPUTextureUsages aUsage);
|
||||||
|
virtual ~ExternalTextureReadBackPresent();
|
||||||
|
|
||||||
|
Maybe<layers::SurfaceDescriptor> ToSurfaceDescriptor(
|
||||||
|
Maybe<gfx::FenceInfo>& aFenceInfo) override {
|
||||||
|
return Nothing();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace webgpu
|
} // namespace webgpu
|
||||||
|
|||||||
@@ -64,6 +64,16 @@ extern bool wgpu_server_ensure_external_texture_for_swap_chain(
|
|||||||
aSwapChainId, aDeviceId, aTextureId, aWidth, aHeight, aFormat, aUsage);
|
aSwapChainId, aDeviceId, aTextureId, aWidth, aHeight, aFormat, aUsage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern void wgpu_server_ensure_external_texture_for_readback(
|
||||||
|
void* aParam, WGPUSwapChainId aSwapChainId, WGPUDeviceId aDeviceId,
|
||||||
|
WGPUTextureId aTextureId, uint32_t aWidth, uint32_t aHeight,
|
||||||
|
struct WGPUTextureFormat aFormat, WGPUTextureUsages aUsage) {
|
||||||
|
auto* parent = static_cast<WebGPUParent*>(aParam);
|
||||||
|
|
||||||
|
parent->EnsureExternalTextureForReadBackPresent(
|
||||||
|
aSwapChainId, aDeviceId, aTextureId, aWidth, aHeight, aFormat, aUsage);
|
||||||
|
}
|
||||||
|
|
||||||
extern void* wgpu_server_get_external_texture_handle(void* aParam,
|
extern void* wgpu_server_get_external_texture_handle(void* aParam,
|
||||||
WGPUTextureId aId) {
|
WGPUTextureId aId) {
|
||||||
auto* parent = static_cast<WebGPUParent*>(aParam);
|
auto* parent = static_cast<WebGPUParent*>(aParam);
|
||||||
@@ -260,6 +270,7 @@ class PresentationData {
|
|||||||
bool mUseExternalTextureInSwapChain;
|
bool mUseExternalTextureInSwapChain;
|
||||||
const RawId mDeviceId;
|
const RawId mDeviceId;
|
||||||
const RawId mQueueId;
|
const RawId mQueueId;
|
||||||
|
Maybe<RawId> mLastSubmittedTextureId;
|
||||||
const layers::RGBDescriptor mDesc;
|
const layers::RGBDescriptor mDesc;
|
||||||
|
|
||||||
uint64_t mSubmissionIndex = 0;
|
uint64_t mSubmissionIndex = 0;
|
||||||
@@ -275,6 +286,8 @@ class PresentationData {
|
|||||||
std::vector<RawId> mAvailableBufferIds;
|
std::vector<RawId> mAvailableBufferIds;
|
||||||
std::vector<RawId> mQueuedBufferIds;
|
std::vector<RawId> mQueuedBufferIds;
|
||||||
|
|
||||||
|
bool mReadbackSnapshotCallbackCalled = false;
|
||||||
|
|
||||||
PresentationData(WebGPUParent* aParent, bool aUseExternalTextureInSwapChain,
|
PresentationData(WebGPUParent* aParent, bool aUseExternalTextureInSwapChain,
|
||||||
RawId aDeviceId, RawId aQueueId,
|
RawId aDeviceId, RawId aQueueId,
|
||||||
const layers::RGBDescriptor& aDesc, uint32_t aSourcePitch,
|
const layers::RGBDescriptor& aDesc, uint32_t aSourcePitch,
|
||||||
@@ -848,6 +861,13 @@ ipc::IPCResult WebGPUParent::RecvQueueSubmit(
|
|||||||
auto& externalTexture = it->second;
|
auto& externalTexture = it->second;
|
||||||
|
|
||||||
externalTexture->SetSubmissionIndex(index);
|
externalTexture->SetSubmissionIndex(index);
|
||||||
|
// Update mLastSubmittedTextureId
|
||||||
|
auto ownerId = externalTexture->GetOwnerId();
|
||||||
|
const auto& lookup = mPresentationDataMap.find(ownerId);
|
||||||
|
if (lookup != mPresentationDataMap.end()) {
|
||||||
|
RefPtr<PresentationData> data = lookup->second.get();
|
||||||
|
data->mLastSubmittedTextureId = Some(textureId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1138,16 +1158,94 @@ static void ReadbackPresentCallback(uint8_t* userdata,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ReadbackSnapshotRequest {
|
||||||
|
ReadbackSnapshotRequest(const ffi::WGPUGlobal* aContext,
|
||||||
|
RefPtr<PresentationData>& aData,
|
||||||
|
ffi::WGPUBufferId aBufferId,
|
||||||
|
const ipc::Shmem& aDestShmem)
|
||||||
|
: mContext(aContext),
|
||||||
|
mData(aData),
|
||||||
|
mBufferId(aBufferId),
|
||||||
|
mDestShmem(aDestShmem) {}
|
||||||
|
|
||||||
|
const ffi::WGPUGlobal* mContext;
|
||||||
|
RefPtr<PresentationData> mData;
|
||||||
|
const ffi::WGPUBufferId mBufferId;
|
||||||
|
const ipc::Shmem& mDestShmem;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void ReadbackSnapshotCallback(uint8_t* userdata,
|
||||||
|
ffi::WGPUBufferMapAsyncStatus status) {
|
||||||
|
UniquePtr<ReadbackSnapshotRequest> req(
|
||||||
|
reinterpret_cast<ReadbackSnapshotRequest*>(userdata));
|
||||||
|
|
||||||
|
RefPtr<PresentationData> data = req->mData;
|
||||||
|
data->mReadbackSnapshotCallbackCalled = true;
|
||||||
|
|
||||||
|
// Ensure we'll make the bufferId available for reuse
|
||||||
|
data->mAvailableBufferIds.push_back(req->mBufferId);
|
||||||
|
|
||||||
|
MOZ_LOG(sLogger, LogLevel::Info,
|
||||||
|
("ReadbackSnapshotCallback for buffer %" PRIu64 " status=%d\n",
|
||||||
|
req->mBufferId, status));
|
||||||
|
if (status != ffi::WGPUBufferMapAsyncStatus_Success) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// copy the data
|
||||||
|
const auto bufferSize = data->mDesc.size().height * data->mSourcePitch;
|
||||||
|
ErrorBuffer getRangeError;
|
||||||
|
const auto mapped = ffi::wgpu_server_buffer_get_mapped_range(
|
||||||
|
req->mContext, req->mBufferId, 0, bufferSize, getRangeError.ToFFI());
|
||||||
|
getRangeError.CoerceValidationToInternal();
|
||||||
|
if (req->mData->mParent) {
|
||||||
|
req->mData->mParent->ForwardError(data->mDeviceId, getRangeError);
|
||||||
|
}
|
||||||
|
if (auto innerError = getRangeError.GetError()) {
|
||||||
|
MOZ_LOG(sLogger, LogLevel::Info,
|
||||||
|
("WebGPU present: buffer get_mapped_range for internal "
|
||||||
|
"presentation readback failed: %s\n",
|
||||||
|
innerError->message.get()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_RELEASE_ASSERT(mapped.length >= bufferSize);
|
||||||
|
|
||||||
|
uint8_t* src = mapped.ptr;
|
||||||
|
uint8_t* dst = req->mDestShmem.get<uint8_t>();
|
||||||
|
const uint32_t stride = layers::ImageDataSerializer::ComputeRGBStride(
|
||||||
|
gfx::SurfaceFormat::B8G8R8A8, data->mDesc.size().width);
|
||||||
|
|
||||||
|
for (auto row = 0; row < data->mDesc.size().height; ++row) {
|
||||||
|
memcpy(dst, src, stride);
|
||||||
|
src += data->mSourcePitch;
|
||||||
|
dst += stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorBuffer unmapError;
|
||||||
|
wgpu_server_buffer_unmap(req->mContext, req->mBufferId, unmapError.ToFFI());
|
||||||
|
unmapError.CoerceValidationToInternal();
|
||||||
|
if (req->mData->mParent) {
|
||||||
|
req->mData->mParent->ForwardError(data->mDeviceId, unmapError);
|
||||||
|
}
|
||||||
|
if (auto innerError = unmapError.GetError()) {
|
||||||
|
MOZ_LOG(sLogger, LogLevel::Info,
|
||||||
|
("WebGPU snapshot: buffer unmap for internal presentation "
|
||||||
|
"readback failed: %s\n",
|
||||||
|
innerError->message.get()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ipc::IPCResult WebGPUParent::GetFrontBufferSnapshot(
|
ipc::IPCResult WebGPUParent::GetFrontBufferSnapshot(
|
||||||
IProtocol* aProtocol, const layers::RemoteTextureOwnerId& aOwnerId,
|
IProtocol* aProtocol, const layers::RemoteTextureOwnerId& aOwnerId,
|
||||||
Maybe<Shmem>& aShmem, gfx::IntSize& aSize) {
|
const RawId& aCommandEncoderId, Maybe<Shmem>& aShmem, gfx::IntSize& aSize) {
|
||||||
const auto& lookup = mPresentationDataMap.find(aOwnerId);
|
const auto& lookup = mPresentationDataMap.find(aOwnerId);
|
||||||
if (lookup == mPresentationDataMap.end() || !mRemoteTextureOwner ||
|
if (lookup == mPresentationDataMap.end()) {
|
||||||
!mRemoteTextureOwner->IsRegistered(aOwnerId)) {
|
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
|
||||||
return IPC_OK();
|
return IPC_OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<PresentationData> data = lookup->second.get();
|
RefPtr<PresentationData> data = lookup->second.get();
|
||||||
|
data->mReadbackSnapshotCallbackCalled = false;
|
||||||
aSize = data->mDesc.size();
|
aSize = data->mDesc.size();
|
||||||
uint32_t stride = layers::ImageDataSerializer::ComputeRGBStride(
|
uint32_t stride = layers::ImageDataSerializer::ComputeRGBStride(
|
||||||
data->mDesc.format(), aSize.width);
|
data->mDesc.format(), aSize.width);
|
||||||
@@ -1157,13 +1255,151 @@ ipc::IPCResult WebGPUParent::GetFrontBufferSnapshot(
|
|||||||
return IPC_OK();
|
return IPC_OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data->mUseExternalTextureInSwapChain) {
|
if (data->mLastSubmittedTextureId.isNothing()) {
|
||||||
ffi::wgpu_server_device_poll(mContext.get(), data->mDeviceId, true);
|
return IPC_OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
mRemoteTextureOwner->GetLatestBufferSnapshot(aOwnerId, shmem, aSize);
|
auto it = mExternalTextures.find(data->mLastSubmittedTextureId.ref());
|
||||||
aShmem.emplace(std::move(shmem));
|
|
||||||
|
|
||||||
|
// ExternalTexture is still in use as no readback
|
||||||
|
if (data->mUseExternalTextureInSwapChain && it != mExternalTextures.end()) {
|
||||||
|
auto& externalTexture = it->second;
|
||||||
|
externalTexture->GetSnapshot(shmem, aSize);
|
||||||
|
return IPC_OK();
|
||||||
|
}
|
||||||
|
|
||||||
|
// External texture is already invalid and posted to RemoteTextureMap
|
||||||
|
if (it != mExternalTextures.end()) {
|
||||||
|
if (!mRemoteTextureOwner || !mRemoteTextureOwner->IsRegistered(aOwnerId)) {
|
||||||
|
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
|
||||||
|
return IPC_OK();
|
||||||
|
}
|
||||||
|
if (!data->mUseExternalTextureInSwapChain) {
|
||||||
|
ffi::wgpu_server_device_poll(mContext.get(), data->mDeviceId, true);
|
||||||
|
}
|
||||||
|
mRemoteTextureOwner->GetLatestBufferSnapshot(aOwnerId, shmem, aSize);
|
||||||
|
aShmem.emplace(std::move(shmem));
|
||||||
|
return IPC_OK();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Readback synchronously
|
||||||
|
|
||||||
|
RawId bufferId = 0;
|
||||||
|
const auto& size = data->mDesc.size();
|
||||||
|
const auto bufferSize = data->mDesc.size().height * data->mSourcePitch;
|
||||||
|
|
||||||
|
// step 1: find an available staging buffer, or create one
|
||||||
|
{
|
||||||
|
if (!data->mAvailableBufferIds.empty()) {
|
||||||
|
bufferId = data->mAvailableBufferIds.back();
|
||||||
|
data->mAvailableBufferIds.pop_back();
|
||||||
|
} else if (!data->mUnassignedBufferIds.empty()) {
|
||||||
|
bufferId = data->mUnassignedBufferIds.back();
|
||||||
|
data->mUnassignedBufferIds.pop_back();
|
||||||
|
|
||||||
|
ffi::WGPUBufferUsages usage =
|
||||||
|
WGPUBufferUsages_COPY_DST | WGPUBufferUsages_MAP_READ;
|
||||||
|
|
||||||
|
ErrorBuffer error;
|
||||||
|
ffi::wgpu_server_device_create_buffer(mContext.get(), data->mDeviceId,
|
||||||
|
bufferId, nullptr, bufferSize,
|
||||||
|
usage, false, false, error.ToFFI());
|
||||||
|
if (ForwardError(data->mDeviceId, error)) {
|
||||||
|
return IPC_OK();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bufferId = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_LOG(sLogger, LogLevel::Info,
|
||||||
|
("GetFrontBufferSnapshot with buffer %" PRIu64 "\n", bufferId));
|
||||||
|
if (!bufferId) {
|
||||||
|
// TODO: add a warning - no buffer are available!
|
||||||
|
return IPC_OK();
|
||||||
|
}
|
||||||
|
|
||||||
|
// step 3: submit a copy command for the frame
|
||||||
|
ffi::WGPUCommandEncoderDescriptor encoderDesc = {};
|
||||||
|
{
|
||||||
|
ErrorBuffer error;
|
||||||
|
ffi::wgpu_server_device_create_encoder(mContext.get(), data->mDeviceId,
|
||||||
|
&encoderDesc, aCommandEncoderId,
|
||||||
|
error.ToFFI());
|
||||||
|
if (ForwardError(data->mDeviceId, error)) {
|
||||||
|
return IPC_OK();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->mLastSubmittedTextureId.isNothing()) {
|
||||||
|
return IPC_OK();
|
||||||
|
}
|
||||||
|
|
||||||
|
const ffi::WGPUTexelCopyTextureInfo texView = {
|
||||||
|
data->mLastSubmittedTextureId.ref(),
|
||||||
|
};
|
||||||
|
const ffi::WGPUTexelCopyBufferLayout bufLayout = {
|
||||||
|
0,
|
||||||
|
&data->mSourcePitch,
|
||||||
|
nullptr,
|
||||||
|
};
|
||||||
|
const ffi::WGPUExtent3d extent = {
|
||||||
|
static_cast<uint32_t>(size.width),
|
||||||
|
static_cast<uint32_t>(size.height),
|
||||||
|
1,
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
ErrorBuffer error;
|
||||||
|
ffi::wgpu_server_encoder_copy_texture_to_buffer(
|
||||||
|
mContext.get(), aCommandEncoderId, &texView, bufferId, &bufLayout,
|
||||||
|
&extent, error.ToFFI());
|
||||||
|
if (ForwardError(data->mDeviceId, error)) {
|
||||||
|
return IPC_OK();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ffi::WGPUCommandBufferDescriptor commandDesc = {};
|
||||||
|
{
|
||||||
|
ErrorBuffer error;
|
||||||
|
ffi::wgpu_server_encoder_finish(mContext.get(), aCommandEncoderId,
|
||||||
|
&commandDesc, error.ToFFI());
|
||||||
|
if (ForwardError(data->mDeviceId, error)) {
|
||||||
|
ffi::wgpu_server_encoder_drop(mContext.get(), aCommandEncoderId);
|
||||||
|
return IPC_OK();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ErrorBuffer error;
|
||||||
|
ffi::wgpu_server_queue_submit(mContext.get(), data->mQueueId,
|
||||||
|
&aCommandEncoderId, 1, error.ToFFI());
|
||||||
|
ffi::wgpu_server_encoder_drop(mContext.get(), aCommandEncoderId);
|
||||||
|
if (ForwardError(data->mDeviceId, error)) {
|
||||||
|
return IPC_OK();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto snapshotRequest = MakeUnique<ReadbackSnapshotRequest>(
|
||||||
|
mContext.get(), data, bufferId, shmem);
|
||||||
|
|
||||||
|
ffi::WGPUBufferMapClosure closure = {
|
||||||
|
&ReadbackSnapshotCallback,
|
||||||
|
reinterpret_cast<uint8_t*>(snapshotRequest.release())};
|
||||||
|
|
||||||
|
ErrorBuffer error;
|
||||||
|
ffi::wgpu_server_buffer_map(mContext.get(), bufferId, 0, bufferSize,
|
||||||
|
ffi::WGPUHostMap_Read, closure, error.ToFFI());
|
||||||
|
if (ForwardError(data->mDeviceId, error)) {
|
||||||
|
return IPC_OK();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback should be called during the poll.
|
||||||
|
ffi::wgpu_server_poll_all_devices(mContext.get(), true);
|
||||||
|
|
||||||
|
// Check if ReadbackSnapshotCallback is called.
|
||||||
|
MOZ_RELEASE_ASSERT(data->mReadbackSnapshotCallbackCalled == true);
|
||||||
|
|
||||||
|
aShmem.emplace(std::move(shmem));
|
||||||
return IPC_OK();
|
return IPC_OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1231,6 +1467,8 @@ ipc::IPCResult WebGPUParent::RecvSwapChainPresent(
|
|||||||
std::shared_ptr<ExternalTexture> externalTexture = it->second;
|
std::shared_ptr<ExternalTexture> externalTexture = it->second;
|
||||||
mExternalTextures.erase(it);
|
mExternalTextures.erase(it);
|
||||||
|
|
||||||
|
MOZ_ASSERT(externalTexture->GetOwnerId() == aOwnerId);
|
||||||
|
|
||||||
PostExternalTexture(std::move(externalTexture), aRemoteTextureId, aOwnerId);
|
PostExternalTexture(std::move(externalTexture), aRemoteTextureId, aOwnerId);
|
||||||
return IPC_OK();
|
return IPC_OK();
|
||||||
}
|
}
|
||||||
@@ -1617,6 +1855,7 @@ bool WebGPUParent::EnsureExternalTextureForSwapChain(
|
|||||||
// Check if the texture is recyclable.
|
// Check if the texture is recyclable.
|
||||||
if (texture->mWidth == aWidth && texture->mHeight == aHeight &&
|
if (texture->mWidth == aWidth && texture->mHeight == aHeight &&
|
||||||
texture->mFormat.tag == aFormat.tag && texture->mUsage == aUsage) {
|
texture->mFormat.tag == aFormat.tag && texture->mUsage == aUsage) {
|
||||||
|
texture->SetOwnerId(ownerId);
|
||||||
data->mRecycledExternalTextures.pop_front();
|
data->mRecycledExternalTextures.pop_front();
|
||||||
mExternalTextures.emplace(aTextureId, texture);
|
mExternalTextures.emplace(aTextureId, texture);
|
||||||
return true;
|
return true;
|
||||||
@@ -1624,14 +1863,44 @@ bool WebGPUParent::EnsureExternalTextureForSwapChain(
|
|||||||
data->mRecycledExternalTextures.clear();
|
data->mRecycledExternalTextures.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto externalTexture = CreateExternalTexture(aDeviceId, aTextureId, aWidth,
|
auto externalTexture = CreateExternalTexture(
|
||||||
aHeight, aFormat, aUsage);
|
ownerId, aDeviceId, aTextureId, aWidth, aHeight, aFormat, aUsage);
|
||||||
return static_cast<bool>(externalTexture);
|
return static_cast<bool>(externalTexture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WebGPUParent::EnsureExternalTextureForReadBackPresent(
|
||||||
|
ffi::WGPUSwapChainId aSwapChainId, ffi::WGPUDeviceId aDeviceId,
|
||||||
|
ffi::WGPUTextureId aTextureId, uint32_t aWidth, uint32_t aHeight,
|
||||||
|
struct ffi::WGPUTextureFormat aFormat, ffi::WGPUTextureUsages aUsage) {
|
||||||
|
auto ownerId = layers::RemoteTextureOwnerId{aSwapChainId._0};
|
||||||
|
const auto& lookup = mPresentationDataMap.find(ownerId);
|
||||||
|
if (lookup == mPresentationDataMap.end()) {
|
||||||
|
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RefPtr<PresentationData> data = lookup->second.get();
|
||||||
|
if (data->mUseExternalTextureInSwapChain) {
|
||||||
|
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UniquePtr<ExternalTexture> texture =
|
||||||
|
ExternalTextureReadBackPresent::Create(aWidth, aHeight, aFormat, aUsage);
|
||||||
|
if (!texture) {
|
||||||
|
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
texture->SetOwnerId(ownerId);
|
||||||
|
std::shared_ptr<ExternalTexture> shared(texture.release());
|
||||||
|
mExternalTextures[aTextureId] = shared;
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<ExternalTexture> WebGPUParent::CreateExternalTexture(
|
std::shared_ptr<ExternalTexture> WebGPUParent::CreateExternalTexture(
|
||||||
ffi::WGPUDeviceId aDeviceId, ffi::WGPUTextureId aTextureId, uint32_t aWidth,
|
const layers::RemoteTextureOwnerId& aOwnerId, ffi::WGPUDeviceId aDeviceId,
|
||||||
uint32_t aHeight, const struct ffi::WGPUTextureFormat aFormat,
|
ffi::WGPUTextureId aTextureId, uint32_t aWidth, uint32_t aHeight,
|
||||||
|
const struct ffi::WGPUTextureFormat aFormat,
|
||||||
ffi::WGPUTextureUsages aUsage) {
|
ffi::WGPUTextureUsages aUsage) {
|
||||||
MOZ_RELEASE_ASSERT(mExternalTextures.find(aTextureId) ==
|
MOZ_RELEASE_ASSERT(mExternalTextures.find(aTextureId) ==
|
||||||
mExternalTextures.end());
|
mExternalTextures.end());
|
||||||
@@ -1642,6 +1911,7 @@ std::shared_ptr<ExternalTexture> WebGPUParent::CreateExternalTexture(
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
texture->SetOwnerId(aOwnerId);
|
||||||
std::shared_ptr<ExternalTexture> shared(texture.release());
|
std::shared_ptr<ExternalTexture> shared(texture.release());
|
||||||
mExternalTextures.emplace(aTextureId, shared);
|
mExternalTextures.emplace(aTextureId, shared);
|
||||||
|
|
||||||
|
|||||||
@@ -135,7 +135,8 @@ class WebGPUParent final : public PWebGPUParent, public SupportsWeakPtr {
|
|||||||
|
|
||||||
ipc::IPCResult GetFrontBufferSnapshot(
|
ipc::IPCResult GetFrontBufferSnapshot(
|
||||||
IProtocol* aProtocol, const layers::RemoteTextureOwnerId& aOwnerId,
|
IProtocol* aProtocol, const layers::RemoteTextureOwnerId& aOwnerId,
|
||||||
Maybe<Shmem>& aShmem, gfx::IntSize& aSize);
|
const RawId& aCommandEncoderId, Maybe<Shmem>& aShmem,
|
||||||
|
gfx::IntSize& aSize);
|
||||||
|
|
||||||
void ActorDestroy(ActorDestroyReason aWhy) override;
|
void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||||
|
|
||||||
@@ -161,9 +162,14 @@ class WebGPUParent final : public PWebGPUParent, public SupportsWeakPtr {
|
|||||||
struct ffi::WGPUTextureFormat aFormat,
|
struct ffi::WGPUTextureFormat aFormat,
|
||||||
ffi::WGPUTextureUsages aUsage);
|
ffi::WGPUTextureUsages aUsage);
|
||||||
|
|
||||||
|
void EnsureExternalTextureForReadBackPresent(
|
||||||
|
ffi::WGPUSwapChainId aSwapChainId, ffi::WGPUDeviceId aDeviceId,
|
||||||
|
ffi::WGPUTextureId aTextureId, uint32_t aWidth, uint32_t aHeight,
|
||||||
|
struct ffi::WGPUTextureFormat aFormat, ffi::WGPUTextureUsages aUsage);
|
||||||
|
|
||||||
std::shared_ptr<ExternalTexture> CreateExternalTexture(
|
std::shared_ptr<ExternalTexture> CreateExternalTexture(
|
||||||
ffi::WGPUDeviceId aDeviceId, ffi::WGPUTextureId aTextureId,
|
const layers::RemoteTextureOwnerId& aOwnerId, ffi::WGPUDeviceId aDeviceId,
|
||||||
uint32_t aWidth, uint32_t aHeight,
|
ffi::WGPUTextureId aTextureId, uint32_t aWidth, uint32_t aHeight,
|
||||||
const struct ffi::WGPUTextureFormat aFormat,
|
const struct ffi::WGPUTextureFormat aFormat,
|
||||||
ffi::WGPUTextureUsages aUsage);
|
ffi::WGPUTextureUsages aUsage);
|
||||||
|
|
||||||
|
|||||||
@@ -230,14 +230,16 @@ layers::ActiveResourceTracker* CanvasManagerChild::GetActiveResourceTracker() {
|
|||||||
|
|
||||||
already_AddRefed<DataSourceSurface> CanvasManagerChild::GetSnapshot(
|
already_AddRefed<DataSourceSurface> CanvasManagerChild::GetSnapshot(
|
||||||
uint32_t aManagerId, int32_t aProtocolId,
|
uint32_t aManagerId, int32_t aProtocolId,
|
||||||
const Maybe<RemoteTextureOwnerId>& aOwnerId, SurfaceFormat aFormat,
|
const Maybe<RemoteTextureOwnerId>& aOwnerId,
|
||||||
|
const Maybe<RawId>& aCommandEncoderId, SurfaceFormat aFormat,
|
||||||
bool aPremultiply, bool aYFlip) {
|
bool aPremultiply, bool aYFlip) {
|
||||||
if (!CanSend()) {
|
if (!CanSend()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
webgl::FrontBufferSnapshotIpc res;
|
webgl::FrontBufferSnapshotIpc res;
|
||||||
if (!SendGetSnapshot(aManagerId, aProtocolId, aOwnerId, &res)) {
|
if (!SendGetSnapshot(aManagerId, aProtocolId, aOwnerId, aCommandEncoderId,
|
||||||
|
&res)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ class CanvasManagerChild final : public PCanvasManagerChild {
|
|||||||
uint32_t Id() const { return mId; }
|
uint32_t Id() const { return mId; }
|
||||||
already_AddRefed<DataSourceSurface> GetSnapshot(
|
already_AddRefed<DataSourceSurface> GetSnapshot(
|
||||||
uint32_t aManagerId, int32_t aProtocolId,
|
uint32_t aManagerId, int32_t aProtocolId,
|
||||||
const Maybe<RemoteTextureOwnerId>& aOwnerId, SurfaceFormat aFormat,
|
const Maybe<RemoteTextureOwnerId>& aOwnerId,
|
||||||
|
const Maybe<RawId>& aCommandEncoderId, SurfaceFormat aFormat,
|
||||||
bool aPremultiply, bool aYFlip);
|
bool aPremultiply, bool aYFlip);
|
||||||
void ActorDestroy(ActorDestroyReason aReason) override;
|
void ActorDestroy(ActorDestroyReason aReason) override;
|
||||||
|
|
||||||
|
|||||||
@@ -180,6 +180,7 @@ CanvasManagerParent::AllocPCanvasParent() {
|
|||||||
mozilla::ipc::IPCResult CanvasManagerParent::RecvGetSnapshot(
|
mozilla::ipc::IPCResult CanvasManagerParent::RecvGetSnapshot(
|
||||||
const uint32_t& aManagerId, const int32_t& aProtocolId,
|
const uint32_t& aManagerId, const int32_t& aProtocolId,
|
||||||
const Maybe<RemoteTextureOwnerId>& aOwnerId,
|
const Maybe<RemoteTextureOwnerId>& aOwnerId,
|
||||||
|
const Maybe<RawId>& aCommandEncoderId,
|
||||||
webgl::FrontBufferSnapshotIpc* aResult) {
|
webgl::FrontBufferSnapshotIpc* aResult) {
|
||||||
if (!aManagerId) {
|
if (!aManagerId) {
|
||||||
return IPC_FAIL(this, "invalid id");
|
return IPC_FAIL(this, "invalid id");
|
||||||
@@ -217,8 +218,11 @@ mozilla::ipc::IPCResult CanvasManagerParent::RecvGetSnapshot(
|
|||||||
if (aOwnerId.isNothing()) {
|
if (aOwnerId.isNothing()) {
|
||||||
return IPC_FAIL(this, "invalid OwnerId");
|
return IPC_FAIL(this, "invalid OwnerId");
|
||||||
}
|
}
|
||||||
mozilla::ipc::IPCResult rv =
|
if (aCommandEncoderId.isNothing()) {
|
||||||
webgpu->GetFrontBufferSnapshot(this, *aOwnerId, buffer.shmem, size);
|
return IPC_FAIL(this, "invalid CommandEncoderId");
|
||||||
|
}
|
||||||
|
mozilla::ipc::IPCResult rv = webgpu->GetFrontBufferSnapshot(
|
||||||
|
this, *aOwnerId, *aCommandEncoderId, buffer.shmem, size);
|
||||||
if (!rv) {
|
if (!rv) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ class CanvasManagerParent final : public PCanvasManagerParent {
|
|||||||
mozilla::ipc::IPCResult RecvGetSnapshot(
|
mozilla::ipc::IPCResult RecvGetSnapshot(
|
||||||
const uint32_t& aManagerId, const int32_t& aProtocolId,
|
const uint32_t& aManagerId, const int32_t& aProtocolId,
|
||||||
const Maybe<RemoteTextureOwnerId>& aOwnerId,
|
const Maybe<RemoteTextureOwnerId>& aOwnerId,
|
||||||
|
const Maybe<RawId>& aCommandEncoderId,
|
||||||
webgl::FrontBufferSnapshotIpc* aResult);
|
webgl::FrontBufferSnapshotIpc* aResult);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ include protocol PWebGPU;
|
|||||||
|
|
||||||
using mozilla::layers::RemoteTextureOwnerId from "mozilla/layers/LayersTypes.h";
|
using mozilla::layers::RemoteTextureOwnerId from "mozilla/layers/LayersTypes.h";
|
||||||
using mozilla::webgl::FrontBufferSnapshotIpc from "mozilla/dom/WebGLIpdl.h";
|
using mozilla::webgl::FrontBufferSnapshotIpc from "mozilla/dom/WebGLIpdl.h";
|
||||||
|
using mozilla::webgpu::RawId from "mozilla/webgpu/WebGPUTypes.h";
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace gfx {
|
namespace gfx {
|
||||||
@@ -45,7 +46,7 @@ parent:
|
|||||||
// intended to be used by the main thread in the content process to block
|
// intended to be used by the main thread in the content process to block
|
||||||
// reading without having to block on the worker thread that owns the context
|
// reading without having to block on the worker thread that owns the context
|
||||||
// instance.
|
// instance.
|
||||||
sync GetSnapshot(uint32_t aManagerId, int32_t aProtocolId, RemoteTextureOwnerId? ownerId) returns (FrontBufferSnapshotIpc ret);
|
sync GetSnapshot(uint32_t aManagerId, int32_t aProtocolId, RemoteTextureOwnerId? ownerId, RawId? commandEncoderId) returns (FrontBufferSnapshotIpc ret);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // gfx
|
} // gfx
|
||||||
|
|||||||
@@ -1414,6 +1414,17 @@ extern "C" {
|
|||||||
usage: wgt::TextureUsages,
|
usage: wgt::TextureUsages,
|
||||||
) -> bool;
|
) -> bool;
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
fn wgpu_server_ensure_external_texture_for_readback(
|
||||||
|
param: *mut c_void,
|
||||||
|
swap_chain_id: SwapChainId,
|
||||||
|
device_id: id::DeviceId,
|
||||||
|
texture_id: id::TextureId,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
format: wgt::TextureFormat,
|
||||||
|
usage: wgt::TextureUsages,
|
||||||
|
);
|
||||||
|
#[allow(dead_code)]
|
||||||
fn wgpu_server_get_external_texture_handle(
|
fn wgpu_server_get_external_texture_handle(
|
||||||
param: *mut c_void,
|
param: *mut c_void,
|
||||||
id: id::TextureId,
|
id: id::TextureId,
|
||||||
@@ -2035,6 +2046,21 @@ impl Global {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(swap_chain_id) = swap_chain_id {
|
||||||
|
unsafe {
|
||||||
|
wgpu_server_ensure_external_texture_for_readback(
|
||||||
|
self.owner,
|
||||||
|
swap_chain_id,
|
||||||
|
self_id,
|
||||||
|
id,
|
||||||
|
desc.size.width,
|
||||||
|
desc.size.height,
|
||||||
|
desc.format,
|
||||||
|
desc.usage,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
let (_, error) = self.device_create_texture(self_id, &desc, Some(id));
|
let (_, error) = self.device_create_texture(self_id, &desc, Some(id));
|
||||||
if let Some(err) = error {
|
if let Some(err) = error {
|
||||||
error_buf.init(err);
|
error_buf.init(err);
|
||||||
|
|||||||
Reference in New Issue
Block a user