Skip to content

Commit

Permalink
Support Bind/CopyTexImage better in passthrough gles decoder.
Browse files Browse the repository at this point in the history
Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:mac_optional_gpu_tests_rel;luci.chromium.try:win_optional_gpu_tests_rel
Change-Id: I02d7fcb62abda9eab421aee71dd8229b5f21ba2c
Reviewed-on: https://chromium-review.googlesource.com/1081232
Reviewed-by: Antoine Labour <piman@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Dan Sanders <sandersd@chromium.org>
Commit-Queue: Frank Liberato <liberato@chromium.org>
Cr-Commit-Position: refs/heads/master@{#565104}
  • Loading branch information
liberato-at-chromium authored and Commit Bot committed Jun 6, 2018
1 parent 6a51082 commit 1d58073
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 26 deletions.
70 changes: 47 additions & 23 deletions gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1481,37 +1481,57 @@ void GLES2DecoderPassthroughImpl::BindImage(uint32_t client_texture_id,

DCHECK(passthrough_texture != nullptr);

// |can_bind_to_sampler| indicates that we don't need to take any action.
// Otherwise, we do it when the texture is first used for drawing.
passthrough_texture->set_is_bind_pending(!can_bind_to_sampler);

GLenum bind_target = GLES2Util::GLFaceTargetToTextureTarget(texture_target);
if (passthrough_texture->target() != bind_target) {
return;
}

if (can_bind_to_sampler) {
// Binding an image to a texture requires that the texture is currently
// bound.
scoped_refptr<TexturePassthrough> current_texture =
bound_textures_[static_cast<size_t>(GLenumToTextureTarget(bind_target))]
[active_texture_unit_]
.texture;
bool bind_new_texture = current_texture != passthrough_texture;
if (bind_new_texture) {
api()->glBindTextureFn(bind_target, passthrough_texture->service_id());
}
// Reference the image even if it is not bound as a sampler.
passthrough_texture->SetLevelImage(texture_target, 0, image);
}

if (!image->BindTexImage(texture_target)) {
image->CopyTexImage(texture_target);
}
void GLES2DecoderPassthroughImpl::BindOnePendingImage(
GLenum target,
TexturePassthrough* texture) {
// It's possible that this texture was processed by some other decoder
// while it was also bound here, or that it has been destroyed. In
// either case, do nothing.
if (!texture || !texture->is_bind_pending())
return;

// Re-bind the old texture
if (bind_new_texture) {
GLuint current_service_texture =
current_texture ? current_texture->service_id() : 0;
api()->glBindTextureFn(bind_target, current_service_texture);
}
}
// TODO(liberato): make this work for non-0 levels.
gl::GLImage* image = texture->GetLevelImage(target, 0);

// Note that we might not have an image anymore, if it was unbound from
// the texture by some other decoder while the texture was still bound
// here. In that case, just ignore it.
//
// Similarly, we might not even get here if an image was bound to a
// texture that requries bind/copy, but that texture was already bound
// to a sampler in this decoder.
if (!image)
return;

// Reference the image even if it is not bound as a sampler.
passthrough_texture->SetLevelImage(texture_target, 0, image);
// TODO: internalformat?
if (!image->BindTexImage(target))
image->CopyTexImage(target);

// If copy / bind fail, then we could keep the bind state the same.
// However, for now, we only try once.
texture->set_is_bind_pending(false);
}

void GLES2DecoderPassthroughImpl::BindPendingImagesForSamplers() {
for (auto iter : textures_pending_binding_)
BindOnePendingImage(iter.first.first /* target */, iter.second.get());

// Note that we clear the texures even if they fail. We could keep
// them around.
textures_pending_binding_.clear();
}

void GLES2DecoderPassthroughImpl::OnDebugMessage(GLenum source,
Expand Down Expand Up @@ -2060,6 +2080,10 @@ error::Error GLES2DecoderPassthroughImpl::BindTexImage2DCHROMIUMImpl(
DCHECK(bound_texture.texture != nullptr);
bound_texture.texture->SetLevelImage(target, 0, image);

// If there was any GLImage bound to |target| on this texture unit, then
// forget it.
textures_pending_binding_.erase(TargetUnitPair(target, active_texture_unit_));

return error::kNoError;
}

Expand Down
44 changes: 44 additions & 0 deletions gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,35 @@ class GPU_GLES2_EXPORT GLES2DecoderPassthroughImpl : public GLES2Decoder {
error::Error CheckSwapBuffersResult(gfx::SwapResult result,
const char* function_name);

// Issue BindTexImage / CopyTexImage calls for |passthrough_texture|, if
// they're pending.
void BindOnePendingImage(GLenum target, TexturePassthrough* texture);

// Issue BindTexImage / CopyTexImage calls for any GLImages that
// requested it in BindImage, and are currently bound to textures that
// are bound to samplers (i.e., are in |textures_pending_binding_|).
void BindPendingImagesForSamplers();

// Fail-fast inline version of BindPendingImagesForSamplers.
inline void BindPendingImagesForSamplersIfNeeded() {
if (textures_pending_binding_.size() > 0)
BindPendingImagesForSamplers();
}

// Fail-fast version of BindPendingImages that operates on a single texture
// that's specified by |client_id|.
inline void BindPendingImageForClientIDIfNeeded(int client_id) {
scoped_refptr<TexturePassthrough> texture = nullptr;

// We could keep track of the number of |is_bind_pending| textures in
// |resources_|, and elide all of this if it's zero.
if (!resources_->texture_object_map.GetServiceID(client_id, &texture))
return;

if (texture && texture->is_bind_pending())
BindOnePendingImage(texture->target(), texture.get());
}

DecoderClient* client_;

int commands_to_process_;
Expand Down Expand Up @@ -522,6 +551,21 @@ class GPU_GLES2_EXPORT GLES2DecoderPassthroughImpl : public GLES2Decoder {
std::array<std::array<BoundTexture, kMaxTextureUnits>, kNumTextureTypes>
bound_textures_;

// [target, texture unit] = texture that has a bound GLImage that requires
// bind / copy before draw.
using TargetUnitPair = std::pair<GLenum, GLuint>;
struct TargetUnitPairHasher {
std::size_t operator()(const TargetUnitPair& target_unit_pair) const {
// Combine them into disjoint ints.
return target_unit_pair.first * kMaxTextureUnits +
target_unit_pair.second;
}
};
std::unordered_map<TargetUnitPair,
base::WeakPtr<TexturePassthrough>,
TargetUnitPairHasher>
textures_pending_binding_;

// State tracking of currently bound buffers
std::unordered_map<GLenum, GLuint> bound_buffers_;

Expand Down
23 changes: 23 additions & 0 deletions gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,12 @@ error::Error GLES2DecoderPassthroughImpl::DoBindTexture(GLenum target,
DCHECK(GLenumToTextureTarget(target) != TextureTarget::kUnkown);
scoped_refptr<TexturePassthrough> texture_passthrough = nullptr;

TargetUnitPair target_unit_pair(target, active_texture_unit_);

// If there was anything bound to |target_unit_pair| that required an image
// bind / copy, forget it since it's no longer bound to a sampler.
textures_pending_binding_.erase(target_unit_pair);

if (service_id != 0) {
// Create a new texture object to track this texture
if (!resources_->texture_object_map.GetServiceID(texture,
Expand All @@ -479,6 +485,15 @@ error::Error GLES2DecoderPassthroughImpl::DoBindTexture(GLenum target,
// target than the one it was just bound to
DCHECK(texture_passthrough->target() == target);
}

DCHECK(texture_passthrough);

// If |texture_passthrough| has a bound image that requires processing
// before a draw, then keep track of it.
if (texture_passthrough->is_bind_pending()) {
textures_pending_binding_[target_unit_pair] =
texture_passthrough->AsWeakPtr();
}
}

BoundTexture* bound_texture =
Expand Down Expand Up @@ -1022,6 +1037,7 @@ error::Error GLES2DecoderPassthroughImpl::DoDisableVertexAttribArray(
error::Error GLES2DecoderPassthroughImpl::DoDrawArrays(GLenum mode,
GLint first,
GLsizei count) {
BindPendingImagesForSamplersIfNeeded();
api()->glDrawArraysFn(mode, first, count);
return error::kNoError;
}
Expand All @@ -1030,6 +1046,7 @@ error::Error GLES2DecoderPassthroughImpl::DoDrawElements(GLenum mode,
GLsizei count,
GLenum type,
const void* indices) {
BindPendingImagesForSamplersIfNeeded();
api()->glDrawElementsFn(mode, count, type, indices);
return error::kNoError;
}
Expand Down Expand Up @@ -1162,6 +1179,7 @@ error::Error GLES2DecoderPassthroughImpl::DoFramebufferTexture2D(
"Cannot change the attachments of the default framebuffer.");
return error::kNoError;
}
BindPendingImageForClientIDIfNeeded(texture);
api()->glFramebufferTexture2DEXTFn(
target, attachment, textarget,
GetTextureServiceID(api(), texture, resources_, false), level);
Expand Down Expand Up @@ -3860,6 +3878,7 @@ error::Error GLES2DecoderPassthroughImpl::DoCopyTextureCHROMIUM(
GLboolean unpack_flip_y,
GLboolean unpack_premultiply_alpha,
GLboolean unpack_unmultiply_alpha) {
BindPendingImageForClientIDIfNeeded(source_id);
api()->glCopyTextureCHROMIUMFn(
GetTextureServiceID(api(), source_id, resources_, false), source_level,
dest_target, GetTextureServiceID(api(), dest_id, resources_, false),
Expand All @@ -3883,6 +3902,7 @@ error::Error GLES2DecoderPassthroughImpl::DoCopySubTextureCHROMIUM(
GLboolean unpack_flip_y,
GLboolean unpack_premultiply_alpha,
GLboolean unpack_unmultiply_alpha) {
BindPendingImageForClientIDIfNeeded(source_id);
api()->glCopySubTextureCHROMIUMFn(
GetTextureServiceID(api(), source_id, resources_, false), source_level,
dest_target, GetTextureServiceID(api(), dest_id, resources_, false),
Expand All @@ -3894,6 +3914,7 @@ error::Error GLES2DecoderPassthroughImpl::DoCopySubTextureCHROMIUM(
error::Error GLES2DecoderPassthroughImpl::DoCompressedCopyTextureCHROMIUM(
GLuint source_id,
GLuint dest_id) {
BindPendingImageForClientIDIfNeeded(source_id);
api()->glCompressedCopyTextureCHROMIUMFn(
GetTextureServiceID(api(), source_id, resources_, false),
GetTextureServiceID(api(), dest_id, resources_, false));
Expand All @@ -3905,6 +3926,7 @@ error::Error GLES2DecoderPassthroughImpl::DoDrawArraysInstancedANGLE(
GLint first,
GLsizei count,
GLsizei primcount) {
BindPendingImagesForSamplersIfNeeded();
api()->glDrawArraysInstancedANGLEFn(mode, first, count, primcount);
return error::kNoError;
}
Expand All @@ -3915,6 +3937,7 @@ error::Error GLES2DecoderPassthroughImpl::DoDrawElementsInstancedANGLE(
GLenum type,
const void* indices,
GLsizei primcount) {
BindPendingImagesForSamplersIfNeeded();
api()->glDrawElementsInstancedANGLEFn(mode, count, type, indices, primcount);
return error::kNoError;
}
Expand Down
15 changes: 13 additions & 2 deletions gpu/command_buffer/service/texture_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "base/containers/hash_tables.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "gpu/command_buffer/service/feature_info.h"
#include "gpu/command_buffer/service/gl_utils.h"
#include "gpu/command_buffer/service/memory_tracking.h"
Expand Down Expand Up @@ -45,8 +46,10 @@ class TextureRef;

// A ref-counted version of the TextureBase class that deletes the texture after
// all references have been released.
class TexturePassthrough final : public TextureBase,
public base::RefCounted<TexturePassthrough> {
class TexturePassthrough final
: public TextureBase,
public base::RefCounted<TexturePassthrough>,
public base::SupportsWeakPtr<TexturePassthrough> {
public:
TexturePassthrough(GLuint service_id, GLenum target);

Expand All @@ -57,13 +60,21 @@ class TexturePassthrough final : public TextureBase,
void SetLevelImage(GLenum target, GLint level, gl::GLImage* image);
gl::GLImage* GetLevelImage(GLenum target, GLint level) const;

// Return true if and only if the decoder should BindTexImage / CopyTexImage
// us before sampling.
bool is_bind_pending() const { return is_bind_pending_; }
void set_is_bind_pending(bool is_bind_pending) {
is_bind_pending_ = is_bind_pending;
}

protected:
~TexturePassthrough() override;

private:
friend class base::RefCounted<TexturePassthrough>;

bool have_context_;
bool is_bind_pending_ = false;

// Bound images divided into faces and then levels
std::vector<std::vector<scoped_refptr<gl::GLImage>>> level_images_;
Expand Down
1 change: 0 additions & 1 deletion media/gpu/windows/dxva_video_decode_accelerator_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -726,7 +726,6 @@ DXVAVideoDecodeAccelerator::DXVAVideoDecodeAccelerator(
support_copy_nv12_textures_(gpu_preferences.enable_nv12_dxgi_video &&
!workarounds.disable_nv12_dxgi_video),
support_delayed_copy_nv12_textures_(
!gpu_preferences.use_passthrough_cmd_decoder &&
base::FeatureList::IsEnabled(kDelayCopyNV12Textures) &&
!workarounds.disable_delayed_copy_nv12),
use_dx11_(false),
Expand Down

0 comments on commit 1d58073

Please sign in to comment.