blob: 8a7e8ced8672600768bf5fbb8a7dad9320136c7d [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 "media/gpu/windows/d3d11_texture_wrapper.h"
#include <memory>
#include "gpu/command_buffer/service/mailbox_manager.h"
#include "media/gpu/windows/return_on_failure.h"
namespace media {
Texture2DWrapper::Texture2DWrapper(ComD3D11Texture2D texture)
: texture_(texture) {}
Texture2DWrapper::~Texture2DWrapper() {}
const ComD3D11Texture2D Texture2DWrapper::Texture() const {
return texture_;
}
DefaultTexture2DWrapper::DefaultTexture2DWrapper(ComD3D11Texture2D texture)
: Texture2DWrapper(texture) {}
DefaultTexture2DWrapper::~DefaultTexture2DWrapper() {}
bool DefaultTexture2DWrapper::ProcessTexture(const D3D11PictureBuffer* owner_pb,
MailboxHolderArray* mailbox_dest) {
for (size_t i = 0; i < VideoFrame::kMaxPlanes; i++)
(*mailbox_dest)[i] = mailbox_holders_[i];
return true;
}
bool DefaultTexture2DWrapper::Init(GetCommandBufferHelperCB get_helper_cb,
size_t array_slice,
gfx::Size size,
int textures_per_picture) {
gpu_resources_ = std::make_unique<GpuResources>();
if (!gpu_resources_)
return false;
// Generate mailboxes and holders.
std::vector<gpu::Mailbox> mailboxes;
for (int texture_idx = 0; texture_idx < textures_per_picture; texture_idx++) {
mailboxes.push_back(gpu::Mailbox::Generate());
mailbox_holders_[texture_idx] = gpu::MailboxHolder(
mailboxes[texture_idx], gpu::SyncToken(), GL_TEXTURE_EXTERNAL_OES);
}
// Start construction of the GpuResources.
// We send the texture itself, since we assume that we're using the angle
// device for decoding. Sharing seems not to work very well. Otherwise, we
// would create the texture with KEYED_MUTEX and NTHANDLE, then send along
// a handle that we get from |texture| as an IDXGIResource1.
// TODO(liberato): this should happen on the gpu thread.
return gpu_resources_->Init(std::move(get_helper_cb), array_slice,
std::move(mailboxes), GL_TEXTURE_EXTERNAL_OES,
size, Texture(), textures_per_picture);
return true;
}
DefaultTexture2DWrapper::GpuResources::GpuResources() {}
DefaultTexture2DWrapper::GpuResources::~GpuResources() {
if (helper_ && helper_->MakeContextCurrent()) {
for (uint32_t service_id : service_ids_)
helper_->DestroyTexture(service_id);
}
}
bool DefaultTexture2DWrapper::GpuResources::Init(
GetCommandBufferHelperCB get_helper_cb,
int array_slice,
const std::vector<gpu::Mailbox> mailboxes,
GLenum target,
gfx::Size size,
ComD3D11Texture2D angle_texture,
int textures_per_picture) {
helper_ = get_helper_cb.Run();
if (!helper_ || !helper_->MakeContextCurrent())
return false;
// Create the textures and attach them to the mailboxes.
for (int texture_idx = 0; texture_idx < textures_per_picture; texture_idx++) {
uint32_t service_id =
helper_->CreateTexture(target, GL_RGBA, size.width(), size.height(),
GL_RGBA, GL_UNSIGNED_BYTE);
service_ids_.push_back(service_id);
helper_->ProduceTexture(mailboxes[texture_idx], service_id);
}
// Create the stream for zero-copy use by gl.
EGLDisplay egl_display = gl::GLSurfaceEGL::GetHardwareDisplay();
const EGLint stream_attributes[] = {
EGL_CONSUMER_LATENCY_USEC_KHR,
0,
EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR,
0,
EGL_NONE,
};
EGLStreamKHR stream = eglCreateStreamKHR(egl_display, stream_attributes);
RETURN_ON_FAILURE(!!stream, "Could not create stream", false);
// |stream| will be destroyed when the GLImage is.
// TODO(liberato): for tests, it will be destroyed pretty much at the end of
// this function unless |helper_| retains it. Also, this won't work if we
// have a FakeCommandBufferHelper since the service IDs aren't meaningful.
scoped_refptr<gl::GLImage> gl_image =
base::MakeRefCounted<gl::GLImageDXGI>(size, stream);
gl::ScopedActiveTexture texture0(GL_TEXTURE0);
gl::ScopedTextureBinder texture0_binder(GL_TEXTURE_EXTERNAL_OES,
service_ids_[0]);
gl::ScopedActiveTexture texture1(GL_TEXTURE1);
gl::ScopedTextureBinder texture1_binder(GL_TEXTURE_EXTERNAL_OES,
service_ids_[1]);
EGLAttrib consumer_attributes[] = {
EGL_COLOR_BUFFER_TYPE,
EGL_YUV_BUFFER_EXT,
EGL_YUV_NUMBER_OF_PLANES_EXT,
2,
EGL_YUV_PLANE0_TEXTURE_UNIT_NV,
0,
EGL_YUV_PLANE1_TEXTURE_UNIT_NV,
1,
EGL_NONE,
};
EGLBoolean result = eglStreamConsumerGLTextureExternalAttribsNV(
egl_display, stream, consumer_attributes);
RETURN_ON_FAILURE(result, "Could not set stream consumer", false);
EGLAttrib producer_attributes[] = {
EGL_NONE,
};
result = eglCreateStreamProducerD3DTextureANGLE(egl_display, stream,
producer_attributes);
RETURN_ON_FAILURE(result, "Could not create stream", false);
EGLAttrib frame_attributes[] = {
EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE,
array_slice,
EGL_NONE,
};
result = eglStreamPostD3DTextureANGLE(egl_display, stream,
static_cast<void*>(angle_texture.Get()),
frame_attributes);
RETURN_ON_FAILURE(result, "Could not post texture", false);
result = eglStreamConsumerAcquireKHR(egl_display, stream);
RETURN_ON_FAILURE(result, "Could not post acquire stream", false);
gl::GLImageDXGI* gl_image_dxgi =
static_cast<gl::GLImageDXGI*>(gl_image.get());
gl_image_dxgi->SetTexture(angle_texture, array_slice);
// Bind the image to each texture.
for (size_t texture_idx = 0; texture_idx < service_ids_.size();
texture_idx++) {
helper_->BindImage(service_ids_[texture_idx], gl_image.get(),
false /* client_managed */);
}
return true;
}
} // namespace media