Skip to content

Commit

Permalink
Implement async ReadPixels for the passthrough command decoder.
Browse files Browse the repository at this point in the history
BUG=770696

TEST=GLReadbackTest.ReadPixelsWithPBOAndQuery
TEST=GLES*DecoderPassthroughTest.ReadPixelsAsync*

Cq-Include-Trybots: master.tryserver.chromium.android:android_optional_gpu_tests_rel;master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel
Change-Id: I5194075c8efe7c6b65830ce89719a1b3e048d7bb
Reviewed-on: https://chromium-review.googlesource.com/696022
Reviewed-by: Antoine Labour <piman@chromium.org>
Commit-Queue: Geoff Lang <geofflang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#506721}
  • Loading branch information
vonture authored and Commit Bot committed Oct 5, 2017
1 parent db19870 commit 5899dbd
Show file tree
Hide file tree
Showing 10 changed files with 502 additions and 10 deletions.
1 change: 1 addition & 0 deletions gpu/command_buffer/service/feature_info.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1423,6 +1423,7 @@ void FeatureInfo::InitializeFeatures() {
gl::HasExtension(extensions, "GL_OES_rgb8_rgba8");
feature_flags_.angle_robust_resource_initialization =
gl::HasExtension(extensions, "GL_ANGLE_robust_resource_initialization");
feature_flags_.nv_fence = gl::HasExtension(extensions, "GL_NV_fence");
}

void FeatureInfo::InitializeFloatAndHalfFloatFeatures(
Expand Down
1 change: 1 addition & 0 deletions gpu/command_buffer/service/feature_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ class GPU_EXPORT FeatureInfo : public base::RefCounted<FeatureInfo> {
bool ext_pixel_buffer_object = false;
bool oes_rgb8_rgba8 = false;
bool angle_robust_resource_initialization = false;
bool nv_fence = false;
};

FeatureInfo();
Expand Down
114 changes: 110 additions & 4 deletions gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,14 @@ GLES2DecoderPassthroughImpl::BoundTexture::operator=(const BoundTexture&) =
GLES2DecoderPassthroughImpl::BoundTexture&
GLES2DecoderPassthroughImpl::BoundTexture::operator=(BoundTexture&&) = default;

GLES2DecoderPassthroughImpl::PendingReadPixels::PendingReadPixels() = default;
GLES2DecoderPassthroughImpl::PendingReadPixels::~PendingReadPixels() = default;
GLES2DecoderPassthroughImpl::PendingReadPixels::PendingReadPixels(
PendingReadPixels&&) = default;
GLES2DecoderPassthroughImpl::PendingReadPixels&
GLES2DecoderPassthroughImpl::PendingReadPixels::operator=(PendingReadPixels&&) =
default;

GLES2DecoderPassthroughImpl::EmulatedColorBuffer::EmulatedColorBuffer(
const EmulatedDefaultFramebufferFormat& format_in)
: format(format_in) {
Expand Down Expand Up @@ -793,6 +801,12 @@ bool GLES2DecoderPassthroughImpl::Initialize(
void GLES2DecoderPassthroughImpl::Destroy(bool have_context) {
if (have_context) {
FlushErrors();

// Destroy all pending read pixels operations
for (const PendingReadPixels& pending_read_pixels : pending_read_pixels_) {
glDeleteBuffersARB(1, &pending_read_pixels.buffer_service_id);
}
pending_read_pixels_.clear();
}

if (!have_context) {
Expand Down Expand Up @@ -1210,11 +1224,14 @@ void GLES2DecoderPassthroughImpl::ProcessPendingQueries(bool did_finish) {
}

bool GLES2DecoderPassthroughImpl::HasMoreIdleWork() const {
return gpu_tracer_->HasTracesToProcess();
return gpu_tracer_->HasTracesToProcess() || !pending_read_pixels_.empty() ||
!pending_queries_.empty();
}

void GLES2DecoderPassthroughImpl::PerformIdleWork() {
gpu_tracer_->ProcessTraces();
ProcessReadPixels(false);
ProcessQueries(false);
}

bool GLES2DecoderPassthroughImpl::HasPollingWork() const {
Expand Down Expand Up @@ -1589,8 +1606,19 @@ GLenum GLES2DecoderPassthroughImpl::PopError() {
}

bool GLES2DecoderPassthroughImpl::FlushErrors() {
auto get_next_error = [this]() {
// Always read a real GL error so that it can be replaced by the injected
// error
GLenum error = glGetError();
if (!injected_driver_errors_.empty()) {
error = injected_driver_errors_.front();
injected_driver_errors_.pop_front();
}
return error;
};

bool had_error = false;
GLenum error = glGetError();
GLenum error = get_next_error();
while (error != GL_NO_ERROR) {
errors_.insert(error);
had_error = true;
Expand All @@ -1609,11 +1637,15 @@ bool GLES2DecoderPassthroughImpl::FlushErrors() {
break;
}

error = glGetError();
error = get_next_error();
}
return had_error;
}

void GLES2DecoderPassthroughImpl::InjectDriverError(GLenum error) {
injected_driver_errors_.push_back(error);
}

bool GLES2DecoderPassthroughImpl::CheckResetStatus() {
DCHECK(!WasContextLost());
DCHECK(context_->IsCurrent(nullptr));
Expand Down Expand Up @@ -1683,9 +1715,20 @@ error::Error GLES2DecoderPassthroughImpl::ProcessQueries(bool did_finish) {
break;

case GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM:
// TODO: Use a fence and do a real async readback
// Initialize the result to being available. Will be marked as
// unavailable if any pending read pixels operations reference this
// query.
result_available = GL_TRUE;
result = GL_TRUE;
for (const PendingReadPixels& pending_read_pixels :
pending_read_pixels_) {
if (pending_read_pixels.waiting_async_pack_queries.count(
query.service_id) > 0) {
result_available = GL_FALSE;
result = GL_FALSE;
break;
}
}
break;

case GL_GET_ERROR_QUERY_CHROMIUM:
Expand Down Expand Up @@ -1746,6 +1789,69 @@ void GLES2DecoderPassthroughImpl::RemovePendingQuery(GLuint service_id) {
}
}

error::Error GLES2DecoderPassthroughImpl::ProcessReadPixels(bool did_finish) {
while (!pending_read_pixels_.empty()) {
const PendingReadPixels& pending_read_pixels = pending_read_pixels_.front();
if (did_finish || pending_read_pixels.fence->HasCompleted()) {
using Result = cmds::ReadPixels::Result;
Result* result = nullptr;
if (pending_read_pixels.result_shm_id != 0) {
result = GetSharedMemoryAs<Result*>(
pending_read_pixels.result_shm_id,
pending_read_pixels.result_shm_offset, sizeof(*result));
if (!result) {
glDeleteBuffersARB(1, &pending_read_pixels.buffer_service_id);
pending_read_pixels_.pop_front();
break;
}
}

void* pixels =
GetSharedMemoryAs<void*>(pending_read_pixels.pixels_shm_id,
pending_read_pixels.pixels_shm_offset,
pending_read_pixels.pixels_size);
if (!pixels) {
glDeleteBuffersARB(1, &pending_read_pixels.buffer_service_id);
pending_read_pixels_.pop_front();
break;
}

glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB,
pending_read_pixels.buffer_service_id);
void* data = nullptr;
if (feature_info_->feature_flags().map_buffer_range) {
data =
glMapBufferRange(GL_PIXEL_PACK_BUFFER_ARB, 0,
pending_read_pixels.pixels_size, GL_MAP_READ_BIT);
} else {
data = glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);
}
if (!data) {
InsertError(GL_OUT_OF_MEMORY, "Failed to map pixel pack buffer.");
pending_read_pixels_.pop_front();
break;
}

memcpy(pixels, data, pending_read_pixels.pixels_size);
glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB);
glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB,
resources_->buffer_id_map.GetServiceIDOrInvalid(
bound_buffers_[GL_PIXEL_PACK_BUFFER_ARB]));
glDeleteBuffersARB(1, &pending_read_pixels.buffer_service_id);

if (result != nullptr) {
result->success = 1;
}

pending_read_pixels_.pop_front();
}
}

// If glFinish() has been called, all of our fences should be completed.
DCHECK(!did_finish || pending_read_pixels_.empty());
return error::kNoError;
}

void GLES2DecoderPassthroughImpl::UpdateTextureBinding(
GLenum target,
GLuint client_id,
Expand Down
39 changes: 39 additions & 0 deletions gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,14 @@
#include "gpu/command_buffer/service/texture_manager.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_fence.h"
#include "ui/gl/gl_image.h"
#include "ui/gl/gl_surface.h"

namespace gl {
class GLFence;
}

namespace gpu {
namespace gles2 {

Expand Down Expand Up @@ -284,6 +289,9 @@ class GPU_EXPORT GLES2DecoderPassthroughImpl : public GLES2Decoder {
bool can_bind_to_sampler) override;

private:
// Allow unittests to inspect internal state tracking
friend class GLES2DecoderPassthroughTestBase;

const char* GetCommandName(unsigned int command_id) const;

void* GetScratchMemory(size_t size);
Expand Down Expand Up @@ -336,13 +344,19 @@ class GPU_EXPORT GLES2DecoderPassthroughImpl : public GLES2Decoder {
GLenum PopError();
bool FlushErrors();

// Inject a driver-level GL error that will replace the result of the next
// call to glGetError
void InjectDriverError(GLenum error);

bool CheckResetStatus();
bool IsRobustnessSupported();

bool IsEmulatedQueryTarget(GLenum target) const;
error::Error ProcessQueries(bool did_finish);
void RemovePendingQuery(GLuint service_id);

error::Error ProcessReadPixels(bool did_finish);

void UpdateTextureBinding(GLenum target,
GLuint client_id,
TexturePassthrough* texture);
Expand Down Expand Up @@ -467,6 +481,31 @@ class GPU_EXPORT GLES2DecoderPassthroughImpl : public GLES2Decoder {
};
std::unordered_map<GLenum, ActiveQuery> active_queries_;

// Pending async ReadPixels calls
struct PendingReadPixels {
PendingReadPixels();
~PendingReadPixels();
PendingReadPixels(PendingReadPixels&&);
PendingReadPixels& operator=(PendingReadPixels&&);

std::unique_ptr<gl::GLFence> fence = nullptr;
GLuint buffer_service_id = 0;
uint32_t pixels_size = 0;
uint32_t pixels_shm_id = 0;
uint32_t pixels_shm_offset = 0;
uint32_t result_shm_id = 0;
uint32_t result_shm_offset = 0;

// Service IDs of GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM queries waiting for
// this read pixels operation to complete
base::flat_set<GLuint> waiting_async_pack_queries;

DISALLOW_COPY_AND_ASSIGN(PendingReadPixels);
};
base::circular_deque<PendingReadPixels> pending_read_pixels_;

// Error state
base::circular_deque<GLenum> injected_driver_errors_;
std::set<GLenum> errors_;

// Default framebuffer emulation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,20 @@ error::Error DoReadPixels(GLint x,
GLsizei* rows,
void* pixels,
int32_t* success);
error::Error DoReadPixelsAsync(GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLenum format,
GLenum type,
GLsizei bufsize,
GLsizei* length,
GLsizei* columns,
GLsizei* rows,
uint32_t pixels_shm_id,
uint32_t pixels_shm_offset,
uint32_t result_shm_id,
uint32_t result_shm_offset);
error::Error DoReleaseShaderCompiler();
error::Error DoRenderbufferStorage(GLenum target,
GLenum internalformat,
Expand Down
Loading

0 comments on commit 5899dbd

Please sign in to comment.