Index: ui/ozone/platform/dri/gbm_surface.cc |
diff --git a/ui/ozone/platform/dri/gbm_surface.cc b/ui/ozone/platform/dri/gbm_surface.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..61f5fb751269fc4a7c1e95a3bbb74fac511558f1 |
--- /dev/null |
+++ b/ui/ozone/platform/dri/gbm_surface.cc |
@@ -0,0 +1,206 @@ |
+// Copyright 2013 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 "ui/ozone/platform/dri/gbm_surface.h" |
+ |
+#include <gbm.h> |
+ |
+#include "base/logging.h" |
+#include "third_party/skia/include/core/SkImageInfo.h" |
+#include "ui/ozone/platform/dri/dri_buffer.h" |
+#include "ui/ozone/platform/dri/dri_wrapper.h" |
+#include "ui/ozone/platform/dri/gbm_surface.h" |
+#include "ui/ozone/platform/dri/hardware_display_controller.h" |
+ |
+namespace ui { |
+ |
+namespace { |
+ |
+// Pixel configuration for the current buffer format. |
+// TODO(dnicoara) These will need to change once we'll query the hardware for |
+// supported configurations. |
+const uint8_t kColorDepth = 24; |
+const uint8_t kPixelDepth = 32; |
+ |
+class BufferData { |
+ public: |
+ // When we create the BufferData we need to register the buffer. Once |
+ // successfully registered, the |framebuffer_| field will hold the ID of the |
+ // buffer. The controller will use this ID when scanning out the buffer. On |
+ // creation we will also associate the BufferData with the buffer. |
+ static BufferData* CreateData(DriWrapper* dri, gbm_bo* buffer); |
+ |
+ // Callback used by GBM to destory the BufferData associated with a buffer. |
+ static void Destroy(gbm_bo* buffer, void* data); |
+ |
+ // Returns the BufferData associated with |buffer|. NULL if no data is |
+ // associated. |
+ static BufferData* GetData(gbm_bo* buffer); |
+ |
+ uint32_t framebuffer() const { return framebuffer_; } |
+ uint32_t handle() const { return handle_; } |
+ |
+ private: |
+ BufferData(DriWrapper* dri, gbm_bo* buffer); |
+ ~BufferData(); |
+ |
+ DriWrapper* dri_; |
+ |
+ uint32_t handle_; |
+ |
+ // ID provided by the controller when the buffer is registered. This ID is |
+ // used when scanning out the buffer. |
+ uint32_t framebuffer_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(BufferData); |
+}; |
+ |
+BufferData::BufferData(DriWrapper* dri, gbm_bo* buffer) |
+ : dri_(dri), |
+ handle_(gbm_bo_get_handle(buffer).u32), |
+ framebuffer_(0) { |
+ // Register the buffer with the controller. This will allow us to scan out the |
+ // buffer once we're done drawing into it. If we can't register the buffer |
+ // then there's no point in having BufferData associated with it. |
+ if (!dri_->AddFramebuffer(gbm_bo_get_width(buffer), |
+ gbm_bo_get_height(buffer), |
+ kColorDepth, |
+ kPixelDepth, |
+ gbm_bo_get_stride(buffer), |
+ handle_, |
+ &framebuffer_)) { |
+ LOG(ERROR) << "Failed to register buffer"; |
+ } |
+} |
+ |
+BufferData::~BufferData() { |
+ if (framebuffer_) |
+ dri_->RemoveFramebuffer(framebuffer_); |
+} |
+ |
+// static |
+BufferData* BufferData::CreateData(DriWrapper* dri, |
+ gbm_bo* buffer) { |
+ BufferData* data = new BufferData(dri, buffer); |
+ if (!data->framebuffer()) { |
+ delete data; |
+ return NULL; |
+ } |
+ |
+ // GBM can destroy the buffers at any time as long as they aren't locked. This |
+ // sets a callback such that we can clean up all our state when GBM destroys |
+ // the buffer. |
+ gbm_bo_set_user_data(buffer, data, BufferData::Destroy); |
+ |
+ return data; |
+} |
+ |
+// static |
+void BufferData::Destroy(gbm_bo* buffer, void* data) { |
+ BufferData* bd = static_cast<BufferData*>(data); |
+ delete bd; |
+} |
+ |
+// static |
+BufferData* BufferData::GetData(gbm_bo* buffer) { |
+ return static_cast<BufferData*>(gbm_bo_get_user_data(buffer)); |
+} |
+ |
+} // namespace |
+ |
+GbmSurface::GbmSurface(gbm_device* device, |
+ DriWrapper* dri, |
+ const gfx::Size& size) |
+ : gbm_device_(device), |
+ dri_(dri), |
+ size_(size), |
+ native_surface_(NULL), |
+ buffers_(), |
+ front_buffer_(0) { |
+ for (size_t i = 0; i < arraysize(buffers_); ++i) |
+ buffers_[i] = NULL; |
+} |
+ |
+GbmSurface::~GbmSurface() { |
+ for (size_t i = 0; i < arraysize(buffers_); ++i) { |
+ if (buffers_[i]) { |
+ gbm_surface_release_buffer(native_surface_, buffers_[i]); |
+ } |
+ } |
+ |
+ if (native_surface_) |
+ gbm_surface_destroy(native_surface_); |
+} |
+ |
+bool GbmSurface::Initialize() { |
+ // TODO(dnicoara) Check underlying system support for pixel format. |
+ native_surface_ = gbm_surface_create( |
+ gbm_device_, |
+ size_.width(), |
+ size_.height(), |
+ GBM_BO_FORMAT_XRGB8888, |
+ GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); |
+ |
+ if (!native_surface_) |
+ return false; |
+ |
+ dumb_buffer_.reset(new DriBuffer(dri_)); |
+ if (!dumb_buffer_->Initialize(SkImageInfo::MakeN32Premul(size_.width(), |
+ size_.height()))) |
+ return false; |
+ |
+ return true; |
+} |
+ |
+uint32_t GbmSurface::GetFramebufferId() const { |
+ if (!buffers_[front_buffer_ ^ 1]) |
+ return dumb_buffer_->framebuffer(); |
+ |
+ BufferData* data = BufferData::GetData(buffers_[front_buffer_ ^ 1]); |
+ CHECK(data); |
+ return data->framebuffer(); |
+} |
+ |
+uint32_t GbmSurface::GetHandle() const { |
+ if (!buffers_[front_buffer_ ^ 1]) |
+ return dumb_buffer_->handle(); |
+ |
+ BufferData* data = BufferData::GetData(buffers_[front_buffer_ ^ 1]); |
+ CHECK(data); |
+ return data->handle(); |
+} |
+ |
+gfx::Size GbmSurface::Size() const { |
+ return size_; |
+} |
+ |
+void GbmSurface::SwapBuffers() { |
+ // If there was a frontbuffer, is no longer active. Release it back to GBM. |
+ if (buffers_[front_buffer_]) |
+ gbm_surface_release_buffer(native_surface_, buffers_[front_buffer_]); |
+ |
+ // Update the index to the frontbuffer. |
+ front_buffer_ ^= 1; |
+ // We've just released it. Since GBM doesn't guarantee we'll get the same |
+ // buffer back, we set it to NULL so we don't keep track of objects that may |
+ // have been destroyed. |
+ buffers_[front_buffer_ ^ 1] = NULL; |
+} |
+ |
+void GbmSurface::LockCurrentDrawable() { |
+ CHECK(native_surface_); |
+ // Lock the buffer we want to display. |
+ buffers_[front_buffer_ ^ 1] = gbm_surface_lock_front_buffer(native_surface_); |
+ |
+ BufferData* data = BufferData::GetData(buffers_[front_buffer_ ^ 1]); |
+ // If it is a new buffer, it won't have any data associated with it. So we |
+ // create it. On creation it will associate itself with the buffer and |
+ // register the buffer. |
+ if (!data) { |
+ data = BufferData::CreateData(dri_, buffers_[front_buffer_ ^ 1]); |
+ DCHECK(data) << "Failed to associate the buffer with the controller"; |
+ } |
+} |
+ |
+} // namespace ui |