blob: 06d4e5fb0a5d23c944a0d7be00eb2ee3d2becdd3 [file] [log] [blame]
// Copyright 2017 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 "base/at_exit.h"
#include "base/command_line.h"
#include "base/message_loop/message_loop.h"
#include "base/stl_util.h"
#include "components/exo/wayland/clients/client_base.h"
#include "components/exo/wayland/clients/client_helper.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/gpu/GrContext.h"
namespace exo {
namespace wayland {
namespace clients {
namespace {
void FrameCallback(void* data, wl_callback* callback, uint32_t time) {
bool* callback_pending = static_cast<bool*>(data);
*callback_pending = false;
}
} // namespace
class VulkanClient : ClientBase {
public:
VulkanClient() {}
void Run(const ClientBase::InitParams& params);
private:
friend class ScopedVulkanRenderFrame;
DISALLOW_COPY_AND_ASSIGN(VulkanClient);
};
// ScopedVulkanRenderFrame class helps setting up all the state needed to begin
// a new frame using vulkan, it creates a command buffer and starts a render
// pass. When destroyed it takes care of submitting to the queue and to wait for
// the work to be done.
class ScopedVulkanRenderFrame {
public:
ScopedVulkanRenderFrame(VulkanClient* client,
VkFramebuffer framebuffer,
SkColor clear_color)
: client_(client) {
static const VkCommandBufferBeginInfo vk_command_buffer_begin_info{
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
};
VkCommandBufferAllocateInfo command_buffer_allocate_info{
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
.commandPool = client->vk_command_pool_->get(),
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
.commandBufferCount = 1,
};
VkResult result = vkAllocateCommandBuffers(client_->vk_device_->get(),
&command_buffer_allocate_info,
&command_buffer_);
CHECK_EQ(VK_SUCCESS, result) << "Failed to create a Vulkan command buffer.";
result =
vkBeginCommandBuffer(command_buffer_, &vk_command_buffer_begin_info);
CHECK_EQ(VK_SUCCESS, result);
SkColor4f sk_color = SkColor4f::FromColor(clear_color);
VkClearValue clear_value = {
.color =
{
.float32 =
{
sk_color.fR, sk_color.fG, sk_color.fB, sk_color.fA,
},
},
};
VkRenderPassBeginInfo render_pass_begin_info{
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
.renderPass = client_->vk_render_pass_->get(),
.framebuffer = framebuffer,
.renderArea =
(VkRect2D){
.offset = {0, 0},
.extent = {client_->surface_size_.width(),
client_->surface_size_.height()},
},
.clearValueCount = 1,
.pClearValues = &clear_value,
};
vkCmdBeginRenderPass(command_buffer_, &render_pass_begin_info,
VK_SUBPASS_CONTENTS_INLINE);
}
~ScopedVulkanRenderFrame() {
vkCmdEndRenderPass(command_buffer_);
VkResult result = vkEndCommandBuffer(command_buffer_);
CHECK_EQ(VK_SUCCESS, result);
VkSubmitInfo submit_info{.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.commandBufferCount = 1,
.pCommandBuffers = &command_buffer_};
result = vkQueueSubmit(client_->vk_queue_, 1, &submit_info, VK_NULL_HANDLE);
CHECK_EQ(VK_SUCCESS, result);
result = vkQueueWaitIdle(client_->vk_queue_);
vkFreeCommandBuffers(client_->vk_device_->get(),
client_->vk_command_pool_->get(), 1, &command_buffer_);
}
private:
VulkanClient* const client_;
VkCommandBuffer command_buffer_ = VK_NULL_HANDLE;
DISALLOW_COPY_AND_ASSIGN(ScopedVulkanRenderFrame);
};
void VulkanClient::Run(const ClientBase::InitParams& params) {
if (!ClientBase::Init(params))
return;
bool callback_pending = false;
std::unique_ptr<wl_callback> frame_callback;
wl_callback_listener frame_listener = {FrameCallback};
size_t frame_count = 0;
do {
if (callback_pending)
continue;
Buffer* buffer = DequeueBuffer();
if (!buffer)
continue;
{
static const SkColor kColors[] = {SK_ColorRED, SK_ColorBLACK,
SK_ColorGREEN};
ScopedVulkanRenderFrame vulkan_frame(
this, buffer->vk_framebuffer->get(),
kColors[++frame_count % base::size(kColors)]);
// This is where the drawing code would go.
// This client is not drawing anything. Just clearing the fb.
}
++frame_count;
wl_surface_set_buffer_scale(surface_.get(), scale_);
wl_surface_set_buffer_transform(surface_.get(), transform_);
wl_surface_damage(surface_.get(), 0, 0, surface_size_.width(),
surface_size_.height());
wl_surface_attach(surface_.get(), buffer->buffer.get(), 0, 0);
frame_callback.reset(wl_surface_frame(surface_.get()));
wl_callback_add_listener(frame_callback.get(), &frame_listener,
&callback_pending);
wl_surface_commit(surface_.get());
wl_display_flush(display_.get());
} while (wl_display_dispatch(display_.get()) != -1);
}
} // namespace clients
} // namespace wayland
} // namespace exo
int main(int argc, char* argv[]) {
base::AtExitManager exit_manager;
base::CommandLine::Init(argc, argv);
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
exo::wayland::clients::ClientBase::InitParams params;
if (!params.FromCommandLine(*command_line))
return 1;
base::MessageLoopForUI message_loop;
exo::wayland::clients::VulkanClient client;
client.Run(params);
return 1;
}