Chromium Code Reviews| 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..e862f151d5a3bc68a026ea56eca64e38f20d505f |
| --- /dev/null |
| +++ b/gpu/command_buffer/tests/fuzzer_main.cc |
| @@ -0,0 +1,237 @@ |
| +// 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(); |
| + CHECK(size <= buffer_->size()); |
| + command_buffer_->SetGetBuffer(buffer_id_); |
| + memcpy(buffer_->memory(), data, size); |
| + command_buffer_->Flush((size + 3) / 4); |
|
no sievers
2016/07/14 21:33:24
don't you want to round down here?
piman
2016/07/14 22:15:46
I was thinking, this gives us slightly more covera
|
| + 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; |
| +} |