| Index: gpu/command_buffer/tests/fuzzer_main.cc
|
| diff --git a/gpu/command_buffer/tests/fuzzer_main.cc b/gpu/command_buffer/tests/fuzzer_main.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..6aa843938ecdffbaec2b39a4523991bb196bf902
|
| --- /dev/null
|
| +++ b/gpu/command_buffer/tests/fuzzer_main.cc
|
| @@ -0,0 +1,243 @@
|
| +// Copyright 2016 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 <stddef.h>
|
| +#include <stdint.h>
|
| +
|
| +#include <memory>
|
| +#include <vector>
|
| +
|
| +#include "base/at_exit.h"
|
| +#include "base/bind.h"
|
| +#include "base/command_line.h"
|
| +#include "base/logging.h"
|
| +#include "base/memory/ref_counted.h"
|
| +#include "build/build_config.h"
|
| +#include "gpu/command_buffer/common/constants.h"
|
| +#include "gpu/command_buffer/common/gles2_cmd_utils.h"
|
| +#include "gpu/command_buffer/common/sync_token.h"
|
| +#include "gpu/command_buffer/service/buffer_manager.h"
|
| +#include "gpu/command_buffer/service/command_buffer_service.h"
|
| +#include "gpu/command_buffer/service/command_executor.h"
|
| +#include "gpu/command_buffer/service/context_group.h"
|
| +#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
|
| +#include "gpu/command_buffer/service/logger.h"
|
| +#include "gpu/command_buffer/service/mailbox_manager_impl.h"
|
| +#include "gpu/command_buffer/service/sync_point_manager.h"
|
| +#include "gpu/command_buffer/service/transfer_buffer_manager.h"
|
| +#include "ui/gfx/geometry/size.h"
|
| +#include "ui/gl/gl_context.h"
|
| +#include "ui/gl/gl_context_stub_with_extensions.h"
|
| +#include "ui/gl/gl_image_ref_counted_memory.h"
|
| +#include "ui/gl/gl_share_group.h"
|
| +#include "ui/gl/gl_stub_api.h"
|
| +#include "ui/gl/gl_surface.h"
|
| +#include "ui/gl/gl_surface_stub.h"
|
| +#include "ui/gl/init/gl_factory.h"
|
| +#include "ui/gl/test/gl_surface_test_support.h"
|
| +
|
| +namespace gpu {
|
| +namespace {
|
| +
|
| +const size_t kCommandBufferSize = 16384;
|
| +const size_t kTransferBufferSize = 16384;
|
| +const size_t kSmallTransferBufferSize = 16;
|
| +const size_t kTinyTransferBufferSize = 3;
|
| +
|
| +class CommandBufferSetup {
|
| + public:
|
| + CommandBufferSetup()
|
| + : atexit_manager_(),
|
| + sync_point_manager_(new SyncPointManager(false)),
|
| + sync_point_order_data_(SyncPointOrderData::Create()),
|
| + mailbox_manager_(new gles2::MailboxManagerImpl),
|
| + share_group_(new gl::GLShareGroup),
|
| + surface_(new gl::GLSurfaceStub),
|
| + context_(new gl::GLContextStub(share_group_.get())),
|
| + command_buffer_id_(CommandBufferId::FromUnsafeValue(1)) {
|
| + logging::SetMinLogLevel(logging::LOG_FATAL);
|
| + base::CommandLine::Init(0, NULL);
|
| + base::CommandLine::ForCurrentProcess()->AppendSwitch(
|
| + switches::kEnableUnsafeES3APIs);
|
| + gpu_preferences_.enable_unsafe_es3_apis = true;
|
| +
|
| + gl::GLSurfaceTestSupport::InitializeOneOffWithMockBindings();
|
| + gl::SetStubGLApi(&api_);
|
| +
|
| + sync_point_client_ = sync_point_manager_->CreateSyncPointClient(
|
| + sync_point_order_data_, CommandBufferNamespace::IN_PROCESS,
|
| + command_buffer_id_);
|
| +
|
| + translator_cache_ = new gles2::ShaderTranslatorCache(gpu_preferences_);
|
| + completeness_cache_ = new gles2::FramebufferCompletenessCache;
|
| + }
|
| +
|
| + void InitDecoder() {
|
| + context_->MakeCurrent(surface_.get());
|
| + scoped_refptr<gles2::FeatureInfo> feature_info =
|
| + new gles2::FeatureInfo();
|
| + scoped_refptr<gles2::ContextGroup> context_group = new gles2::ContextGroup(
|
| + gpu_preferences_, mailbox_manager_.get(), nullptr, translator_cache_,
|
| + completeness_cache_, feature_info, true /* bind_generates_resource */,
|
| + nullptr /* ImageFactory */);
|
| + command_buffer_.reset(
|
| + new CommandBufferService(context_group->transfer_buffer_manager()));
|
| + command_buffer_->SetPutOffsetChangeCallback(
|
| + base::Bind(&CommandBufferSetup::PumpCommands, base::Unretained(this)));
|
| + command_buffer_->SetGetBufferChangeCallback(base::Bind(
|
| + &CommandBufferSetup::GetBufferChanged, base::Unretained(this)));
|
| + InitializeInitialCommandBuffer();
|
| +
|
| + decoder_.reset(gles2::GLES2Decoder::Create(context_group.get()));
|
| + executor_.reset(new CommandExecutor(command_buffer_.get(), decoder_.get(),
|
| + decoder_.get()));
|
| + decoder_->set_engine(executor_.get());
|
| + decoder_->SetFenceSyncReleaseCallback(base::Bind(
|
| + &CommandBufferSetup::OnFenceSyncRelease, base::Unretained(this)));
|
| + decoder_->SetWaitFenceSyncCallback(base::Bind(
|
| + &CommandBufferSetup::OnWaitFenceSync, base::Unretained(this)));
|
| + decoder_->GetLogger()->set_log_synthesized_gl_errors(false);
|
| +
|
| + gles2::ContextCreationAttribHelper attrib_helper;
|
| + attrib_helper.offscreen_framebuffer_size = gfx::Size(16, 16);
|
| + attrib_helper.red_size = 8;
|
| + attrib_helper.green_size = 8;
|
| + attrib_helper.blue_size = 8;
|
| + attrib_helper.alpha_size = 8;
|
| + attrib_helper.depth_size = 0;
|
| + attrib_helper.stencil_size = 0;
|
| + attrib_helper.context_type = gles2::CONTEXT_TYPE_OPENGLES3;
|
| +
|
| + bool result =
|
| + decoder_->Initialize(surface_.get(), context_.get(), true,
|
| + gles2::DisallowedFeatures(), attrib_helper);
|
| + CHECK(result);
|
| + decoder_->set_max_bucket_size(8 << 20);
|
| + context_group->buffer_manager()->set_max_buffer_size(8 << 20);
|
| + }
|
| +
|
| + void ResetDecoder() {
|
| + decoder_->Destroy(true);
|
| + decoder_.reset();
|
| + command_buffer_.reset();
|
| + }
|
| +
|
| + ~CommandBufferSetup() {
|
| + sync_point_client_ = nullptr;
|
| + if (sync_point_order_data_) {
|
| + sync_point_order_data_->Destroy();
|
| + sync_point_order_data_ = nullptr;
|
| + }
|
| + }
|
| +
|
| + void RunCommandBuffer(const uint8_t* data, size_t size) {
|
| + InitDecoder();
|
| + // The commands are flushed at a uint32_t granularity. If the data is not
|
| + // a full command, we zero-pad it.
|
| + size_t padded_size = (size + 3) & ~3;
|
| + CHECK_LE(padded_size, buffer_->size());
|
| + command_buffer_->SetGetBuffer(buffer_id_);
|
| + auto* memory = static_cast<char*>(buffer_->memory());
|
| + memcpy(memory, data, size);
|
| + if (padded_size > size)
|
| + memset(memory + size, 0, padded_size - size);
|
| + command_buffer_->Flush(padded_size / 4);
|
| + ResetDecoder();
|
| + }
|
| +
|
| + private:
|
| + void PumpCommands() {
|
| + if (!decoder_->MakeCurrent()) {
|
| + command_buffer_->SetContextLostReason(decoder_->GetContextLostReason());
|
| + command_buffer_->SetParseError(::gpu::error::kLostContext);
|
| + return;
|
| + }
|
| +
|
| + uint32_t order_num = sync_point_order_data_->GenerateUnprocessedOrderNumber(
|
| + sync_point_manager_.get());
|
| + sync_point_order_data_->BeginProcessingOrderNumber(order_num);
|
| +
|
| + executor_->PutChanged();
|
| +
|
| + sync_point_order_data_->FinishProcessingOrderNumber(order_num);
|
| + }
|
| +
|
| + bool GetBufferChanged(int32_t transfer_buffer_id) {
|
| + return executor_->SetGetBuffer(transfer_buffer_id);
|
| + }
|
| +
|
| + void OnFenceSyncRelease(uint64_t release) {
|
| + CHECK(sync_point_client_);
|
| + sync_point_client_->ReleaseFenceSync(release);
|
| + }
|
| +
|
| + bool OnWaitFenceSync(CommandBufferNamespace namespace_id,
|
| + CommandBufferId command_buffer_id,
|
| + uint64_t release) {
|
| + CHECK(sync_point_client_);
|
| + scoped_refptr<gpu::SyncPointClientState> release_state =
|
| + sync_point_manager_->GetSyncPointClientState(namespace_id,
|
| + command_buffer_id);
|
| + if (!release_state)
|
| + return true;
|
| +
|
| + if (release_state->IsFenceSyncReleased(release))
|
| + return true;
|
| +
|
| + executor_->SetScheduled(false);
|
| + return false;
|
| + }
|
| +
|
| + void InitializeInitialCommandBuffer() {
|
| + buffer_id_ = 1;
|
| + buffer_ = command_buffer_->CreateTransferBufferWithId(kCommandBufferSize,
|
| + buffer_id_);
|
| + CHECK(buffer_);
|
| + // Create some transfer buffers. This is somewhat arbitrary, but having a
|
| + // reasonably sized buffer in slot 4 allows us to prime the corpus with data
|
| + // extracted from unit tests.
|
| + command_buffer_->CreateTransferBufferWithId(kTransferBufferSize, 2);
|
| + command_buffer_->CreateTransferBufferWithId(kSmallTransferBufferSize, 3);
|
| + command_buffer_->CreateTransferBufferWithId(kTransferBufferSize, 4);
|
| + command_buffer_->CreateTransferBufferWithId(kTinyTransferBufferSize, 5);
|
| + }
|
| +
|
| + base::AtExitManager atexit_manager_;
|
| +
|
| + gl::GLStubApi api_;
|
| + GpuPreferences gpu_preferences_;
|
| +
|
| + std::unique_ptr<SyncPointManager> sync_point_manager_;
|
| + scoped_refptr<SyncPointOrderData> sync_point_order_data_;
|
| + std::unique_ptr<SyncPointClient> sync_point_client_;
|
| + scoped_refptr<gles2::MailboxManager> mailbox_manager_;
|
| + scoped_refptr<gl::GLShareGroup> share_group_;
|
| + scoped_refptr<gl::GLSurface> surface_;
|
| + scoped_refptr<gl::GLContext> context_;
|
| + const gpu::CommandBufferId command_buffer_id_;
|
| +
|
| + scoped_refptr<gles2::ShaderTranslatorCache> translator_cache_;
|
| + scoped_refptr<gles2::FramebufferCompletenessCache> completeness_cache_;
|
| +
|
| + std::unique_ptr<CommandBufferService> command_buffer_;
|
| +
|
| + std::unique_ptr<gles2::GLES2Decoder> decoder_;
|
| + std::unique_ptr<CommandExecutor> executor_;
|
| +
|
| + scoped_refptr<Buffer> buffer_;
|
| + int32_t buffer_id_ = 0;
|
| +};
|
| +
|
| +} // anonymous namespace
|
| +} // namespace gpu
|
| +
|
| +
|
| +static gpu::CommandBufferSetup& GetSetup() {
|
| + static gpu::CommandBufferSetup setup;
|
| + return setup;
|
| +}
|
| +
|
| +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
| + GetSetup().RunCommandBuffer(data, size);
|
| + return 0;
|
| +}
|
|
|