blob: 65a2db14ff6ca0adb96958aceb5796d1274df5d5 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "gpu/command_buffer/service/external_vk_image_dawn_representation.h"
#include <dawn_native/VulkanBackend.h>
#include <utility>
#include <vector>
#include "base/posix/eintr_wrapper.h"
#include "gpu/vulkan/vulkan_image.h"
namespace gpu {
ExternalVkImageDawnRepresentation::ExternalVkImageDawnRepresentation(
SharedImageManager* manager,
SharedImageBacking* backing,
MemoryTypeTracker* tracker,
WGPUDevice device,
WGPUTextureFormat wgpu_format,
base::ScopedFD memory_fd)
: SharedImageRepresentationDawn(manager, backing, tracker),
device_(device),
wgpu_format_(wgpu_format),
memory_fd_(std::move(memory_fd)),
dawn_procs_(dawn_native::GetProcs()) {
DCHECK(device_);
// Keep a reference to the device so that it stays valid (it might become
// lost in which case operations will be noops).
dawn_procs_.deviceReference(device_);
}
ExternalVkImageDawnRepresentation::~ExternalVkImageDawnRepresentation() {
EndAccess();
dawn_procs_.deviceRelease(device_);
}
WGPUTexture ExternalVkImageDawnRepresentation::BeginAccess(
WGPUTextureUsage usage) {
DCHECK(begin_access_semaphores_.empty());
if (!backing_impl()->BeginAccess(false, &begin_access_semaphores_,
false /* is_gl */)) {
return nullptr;
}
WGPUTextureDescriptor texture_descriptor = {};
texture_descriptor.format = wgpu_format_;
texture_descriptor.usage = usage;
texture_descriptor.dimension = WGPUTextureDimension_2D;
texture_descriptor.size = {static_cast<uint32_t>(size().width()),
static_cast<uint32_t>(size().height()), 1};
texture_descriptor.mipLevelCount = 1;
texture_descriptor.sampleCount = 1;
// We need to have an internal usage of CopySrc in order to use
// CopyTextureToTextureInternal.
WGPUDawnTextureInternalUsageDescriptor internalDesc = {};
internalDesc.chain.sType = WGPUSType_DawnTextureInternalUsageDescriptor;
internalDesc.internalUsage = WGPUTextureUsage_CopySrc;
texture_descriptor.nextInChain =
reinterpret_cast<WGPUChainedStruct*>(&internalDesc);
dawn_native::vulkan::ExternalImageDescriptorOpaqueFD descriptor = {};
descriptor.cTextureDescriptor = &texture_descriptor;
descriptor.isInitialized = IsCleared();
descriptor.allocationSize = backing_impl()->image()->device_size();
descriptor.memoryTypeIndex = backing_impl()->image()->memory_type_index();
descriptor.memoryFD = dup(memory_fd_.get());
const GrBackendTexture& backend_texture = backing_impl()->backend_texture();
GrVkImageInfo image_info;
backend_texture.getVkImageInfo(&image_info);
// We should either be importing the image from the external queue, or it
// was just created with no queue ownership.
DCHECK(image_info.fCurrentQueueFamily == VK_QUEUE_FAMILY_IGNORED ||
image_info.fCurrentQueueFamily == VK_QUEUE_FAMILY_EXTERNAL);
// Note: This assumes the previous owner of the shared image did not do a
// layout transition on EndAccess, and saved the exported layout on the
// GrBackendTexture.
descriptor.releasedOldLayout = image_info.fImageLayout;
descriptor.releasedNewLayout = image_info.fImageLayout;
for (auto& external_semaphore : begin_access_semaphores_) {
descriptor.waitFDs.push_back(
external_semaphore.handle().TakeHandle().release());
}
texture_ = dawn_native::vulkan::WrapVulkanImage(device_, &descriptor);
return texture_;
}
void ExternalVkImageDawnRepresentation::EndAccess() {
if (!texture_) {
return;
}
// Grab the signal semaphore from dawn
dawn_native::vulkan::ExternalImageExportInfoOpaqueFD export_info;
if (!dawn_native::vulkan::ExportVulkanImage(
texture_, VK_IMAGE_LAYOUT_UNDEFINED, &export_info)) {
DLOG(ERROR) << "Failed to export Dawn Vulkan image.";
} else {
if (export_info.isInitialized) {
SetCleared();
}
// Exporting to VK_IMAGE_LAYOUT_UNDEFINED means no transition should be
// done. The old/new layouts are the same.
DCHECK_EQ(export_info.releasedOldLayout, export_info.releasedNewLayout);
// Save the layout on the GrBackendTexture. Other shared image
// representations read it from here.
GrBackendTexture backend_texture = backing_impl()->backend_texture();
backend_texture.setMutableState(GrBackendSurfaceMutableState(
export_info.releasedNewLayout, VK_QUEUE_FAMILY_EXTERNAL));
// TODO(enga): Handle waiting on multiple semaphores from dawn
DCHECK(export_info.semaphoreHandles.size() == 1);
// Wrap file descriptor in a handle
SemaphoreHandle handle(VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR,
base::ScopedFD(export_info.semaphoreHandles[0]));
auto semaphore = ExternalSemaphore::CreateFromHandle(
backing_impl()->context_provider(), std::move(handle));
backing_impl()->EndAccess(false, std::move(semaphore), false /* is_gl */);
}
// Destroy the texture, signaling the semaphore in dawn
dawn_procs_.textureDestroy(texture_);
dawn_procs_.textureRelease(texture_);
texture_ = nullptr;
// We have done with |begin_access_semaphores_|. They should have been waited.
// So add them to pending semaphores for reusing or relaeasing.
backing_impl()->AddSemaphoresToPendingListOrRelease(
std::move(begin_access_semaphores_));
begin_access_semaphores_.clear();
}
} // namespace gpu