1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/at_exit.h"
6 #include "base/command_line.h"
7 #include "base/message_loop/message_pump_type.h"
8 #include "base/stl_util.h"
9 #include "base/task/single_thread_task_executor.h"
10 #include "components/exo/wayland/clients/client_base.h"
11 #include "components/exo/wayland/clients/client_helper.h"
12 #include "gpu/vulkan/vulkan_function_pointers.h"
13 #include "third_party/skia/include/core/SkCanvas.h"
14 #include "third_party/skia/include/core/SkSurface.h"
15 #include "third_party/skia/include/gpu/GrContext.h"
16
17 namespace exo {
18 namespace wayland {
19 namespace clients {
20 namespace {
21
FrameCallback(void * data,wl_callback * callback,uint32_t time)22 void FrameCallback(void* data, wl_callback* callback, uint32_t time) {
23 bool* callback_pending = static_cast<bool*>(data);
24 *callback_pending = false;
25 }
26
27 } // namespace
28
29 class VulkanClient : ClientBase {
30 public:
VulkanClient()31 VulkanClient() {}
32
33 void Run(const ClientBase::InitParams& params);
34
35 private:
36 friend class ScopedVulkanRenderFrame;
37
38 DISALLOW_COPY_AND_ASSIGN(VulkanClient);
39 };
40
41 // ScopedVulkanRenderFrame class helps setting up all the state needed to begin
42 // a new frame using vulkan, it creates a command buffer and starts a render
43 // pass. When destroyed it takes care of submitting to the queue and to wait for
44 // the work to be done.
45 class ScopedVulkanRenderFrame {
46 public:
ScopedVulkanRenderFrame(VulkanClient * client,VkFramebuffer framebuffer,SkColor clear_color)47 ScopedVulkanRenderFrame(VulkanClient* client,
48 VkFramebuffer framebuffer,
49 SkColor clear_color)
50 : client_(client) {
51 static const VkCommandBufferBeginInfo vk_command_buffer_begin_info{
52 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
53 .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
54 };
55
56 VkCommandBufferAllocateInfo command_buffer_allocate_info{
57 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
58 .commandPool = client->vk_command_pool_->get(),
59 .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
60 .commandBufferCount = 1,
61 };
62
63 VkResult result = vkAllocateCommandBuffers(client_->vk_device_->get(),
64 &command_buffer_allocate_info,
65 &command_buffer_);
66 CHECK_EQ(VK_SUCCESS, result) << "Failed to create a Vulkan command buffer.";
67
68 result =
69 vkBeginCommandBuffer(command_buffer_, &vk_command_buffer_begin_info);
70 CHECK_EQ(VK_SUCCESS, result);
71
72 SkColor4f sk_color = SkColor4f::FromColor(clear_color);
73 VkClearValue clear_value = {
74 .color =
75 {
76 .float32 =
77 {
78 sk_color.fR, sk_color.fG, sk_color.fB, sk_color.fA,
79 },
80 },
81 };
82 VkRenderPassBeginInfo render_pass_begin_info{
83 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
84 .renderPass = client_->vk_render_pass_->get(),
85 .framebuffer = framebuffer,
86 .renderArea =
87 (VkRect2D){
88 .offset = {0, 0},
89 .extent = {client_->surface_size_.width(),
90 client_->surface_size_.height()},
91 },
92 .clearValueCount = 1,
93 .pClearValues = &clear_value,
94 };
95 vkCmdBeginRenderPass(command_buffer_, &render_pass_begin_info,
96 VK_SUBPASS_CONTENTS_INLINE);
97 }
~ScopedVulkanRenderFrame()98 ~ScopedVulkanRenderFrame() {
99 vkCmdEndRenderPass(command_buffer_);
100
101 VkResult result = vkEndCommandBuffer(command_buffer_);
102 CHECK_EQ(VK_SUCCESS, result);
103 VkSubmitInfo submit_info{.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
104 .commandBufferCount = 1,
105 .pCommandBuffers = &command_buffer_};
106 result = vkQueueSubmit(client_->vk_queue_, 1, &submit_info, VK_NULL_HANDLE);
107 CHECK_EQ(VK_SUCCESS, result);
108
109 result = vkQueueWaitIdle(client_->vk_queue_);
110
111 vkFreeCommandBuffers(client_->vk_device_->get(),
112 client_->vk_command_pool_->get(), 1, &command_buffer_);
113 }
114
115 private:
116 VulkanClient* const client_;
117 VkCommandBuffer command_buffer_ = VK_NULL_HANDLE;
118
119 DISALLOW_COPY_AND_ASSIGN(ScopedVulkanRenderFrame);
120 };
121
Run(const ClientBase::InitParams & params)122 void VulkanClient::Run(const ClientBase::InitParams& params) {
123 if (!ClientBase::Init(params))
124 return;
125
126 bool callback_pending = false;
127 std::unique_ptr<wl_callback> frame_callback;
128 wl_callback_listener frame_listener = {FrameCallback};
129
130 size_t frame_count = 0;
131 do {
132 if (callback_pending)
133 continue;
134
135 Buffer* buffer = DequeueBuffer();
136 if (!buffer)
137 continue;
138
139 {
140 static const SkColor kColors[] = {SK_ColorRED, SK_ColorBLACK,
141 SK_ColorGREEN};
142
143 ScopedVulkanRenderFrame vulkan_frame(
144 this, buffer->vk_framebuffer->get(),
145 kColors[++frame_count % base::size(kColors)]);
146
147 // This is where the drawing code would go.
148 // This client is not drawing anything. Just clearing the fb.
149 }
150 ++frame_count;
151
152 wl_surface_set_buffer_scale(surface_.get(), scale_);
153 wl_surface_set_buffer_transform(surface_.get(), transform_);
154 wl_surface_damage(surface_.get(), 0, 0, surface_size_.width(),
155 surface_size_.height());
156 wl_surface_attach(surface_.get(), buffer->buffer.get(), 0, 0);
157
158 frame_callback.reset(wl_surface_frame(surface_.get()));
159 wl_callback_add_listener(frame_callback.get(), &frame_listener,
160 &callback_pending);
161 wl_surface_commit(surface_.get());
162 wl_display_flush(display_.get());
163 } while (wl_display_dispatch(display_.get()) != -1);
164 }
165
166 } // namespace clients
167 } // namespace wayland
168 } // namespace exo
169
main(int argc,char * argv[])170 int main(int argc, char* argv[]) {
171 base::AtExitManager exit_manager;
172 base::CommandLine::Init(argc, argv);
173 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
174
175 exo::wayland::clients::ClientBase::InitParams params;
176 if (!params.FromCommandLine(*command_line))
177 return 1;
178
179 params.use_vulkan = true;
180 base::SingleThreadTaskExecutor main_task_executor(base::MessagePumpType::UI);
181 exo::wayland::clients::VulkanClient client;
182 client.Run(params);
183 return 1;
184 }
185