| // Copyright 2017 The Fuchsia 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 "garnet/lib/machina/gpu_bitmap.h" |
| |
| #include <string.h> |
| |
| #include "garnet/lib/machina/virtio_gpu.h" |
| |
| namespace machina { |
| |
| static constexpr uint8_t kSrcPixelSize = 4; |
| |
| bool GpuRect::Overlaps(const GpuRect& o) { |
| if (x > (o.x + o.width) || o.x > (x + width)) { |
| return false; |
| } |
| if (y > (o.y + o.height) || o.y > (y + height)) { |
| return false; |
| } |
| return true; |
| } |
| |
| // NOTE(abdulla): These functions are lightly modified versions of the same |
| // functions in the Zircon GFX library. |
| |
| static void argb8888_to_rgb565(uint8_t* dst, const uint8_t* src, size_t size) { |
| for (size_t i = 0; i < size; i += 4, dst += 2, src += 4) { |
| uint32_t in = *reinterpret_cast<const uint32_t*>(src); |
| uint16_t out = (in >> 3) & 0x1f; // b |
| out |= ((in >> 10) & 0x3f) << 5; // g |
| out |= ((in >> 19) & 0x1f) << 11; // r |
| *reinterpret_cast<uint16_t*>(dst) = out; |
| } |
| } |
| |
| static void argb8888_to_rgb332(uint8_t* dst, const uint8_t* src, size_t size) { |
| for (size_t i = 0; i < size; i += 4, dst += 1, src += 4) { |
| uint32_t in = *reinterpret_cast<const uint32_t*>(src); |
| uint8_t out = (in >> 6) & 0x3; // b |
| out |= ((in >> 13) & 0x7) << 2; // g |
| out |= ((in >> 21) & 0x7) << 5; // r |
| *dst = out; |
| } |
| } |
| |
| static void argb8888_to_rgb2220(uint8_t* dst, const uint8_t* src, size_t size) { |
| for (size_t i = 0; i < size; i += 4, dst += 1, src += 4) { |
| uint32_t in = *reinterpret_cast<const uint32_t*>(src); |
| uint8_t out = ((in >> 6) & 0x3) << 2; // b |
| out |= ((in >> 14) & 0x3) << 4; // g |
| out |= ((in >> 22) & 0x3) << 6; // r |
| *dst = out; |
| } |
| } |
| |
| static void argb8888_to_luma(uint8_t* dst, const uint8_t* src, size_t size) { |
| for (size_t i = 0; i < size; i += 4, dst += 1, src += 4) { |
| uint32_t in = *reinterpret_cast<const uint32_t*>(src); |
| uint32_t b = (in & 0xff) * 74; |
| uint32_t g = ((in >> 8) & 0xff) * 732; |
| uint32_t r = ((in >> 16) & 0xff) * 218; |
| uint32_t intensity = r + b + g; |
| *dst = (intensity >> 10) & 0xff; |
| } |
| } |
| |
| static void copy(uint8_t* dst, const uint8_t* src, size_t size, |
| zx_pixel_format_t format) { |
| switch (format) { |
| case ZX_PIXEL_FORMAT_ARGB_8888: |
| case ZX_PIXEL_FORMAT_RGB_x888: |
| return static_cast<void>(memcpy(dst, src, size)); |
| case ZX_PIXEL_FORMAT_RGB_565: |
| return argb8888_to_rgb565(dst, src, size); |
| case ZX_PIXEL_FORMAT_RGB_332: |
| return argb8888_to_rgb332(dst, src, size); |
| case ZX_PIXEL_FORMAT_RGB_2220: |
| return argb8888_to_rgb2220(dst, src, size); |
| case ZX_PIXEL_FORMAT_GRAY_8: |
| return argb8888_to_luma(dst, src, size); |
| default: |
| ZX_DEBUG_ASSERT(false); |
| } |
| } |
| |
| GpuBitmap::GpuBitmap() : GpuBitmap(0, 0, 0, nullptr) {} |
| |
| GpuBitmap::GpuBitmap(uint32_t width, uint32_t height, zx_pixel_format_t format, |
| uint8_t* ptr) |
| : GpuBitmap(width, height, width, format, ptr) {} |
| |
| GpuBitmap::GpuBitmap(uint32_t width, uint32_t height, uint32_t stride, |
| zx_pixel_format_t format, uint8_t* ptr) |
| : width_(width), |
| height_(height), |
| stride_(stride), |
| format_(format), |
| ptr_(ptr) {} |
| |
| GpuBitmap::GpuBitmap(uint32_t width, uint32_t height, zx_pixel_format_t format) |
| : width_(width), |
| height_(height), |
| stride_(width), |
| format_(format), |
| buffer_(new uint8_t[width * height * pixelsize()]), |
| ptr_(buffer_.get()) {} |
| |
| GpuBitmap::GpuBitmap(GpuBitmap&& o) |
| : width_(o.width_), |
| height_(o.height_), |
| stride_(o.stride_), |
| format_(o.format_), |
| buffer_(fbl::move(o.buffer_)), |
| ptr_(o.ptr_) { |
| o.ptr_ = nullptr; |
| } |
| |
| GpuBitmap& GpuBitmap::operator=(GpuBitmap&& o) { |
| width_ = o.width_; |
| height_ = o.height_; |
| stride_ = o.stride_; |
| format_ = o.format_; |
| buffer_ = fbl::move(o.buffer_); |
| ptr_ = o.ptr_; |
| o.ptr_ = nullptr; |
| return *this; |
| } |
| |
| void GpuBitmap::DrawBitmap(const GpuBitmap& src_bitmap, const GpuRect& src_rect, |
| const GpuRect& dst_rect) { |
| if (src_rect.width != dst_rect.width || src_rect.height != dst_rect.height) { |
| return; |
| } |
| if (src_bitmap.pixelsize() != kSrcPixelSize) { |
| return; |
| } |
| if (src_rect.x > src_bitmap.width() || src_rect.y > src_bitmap.height() || |
| dst_rect.x > width() || dst_rect.y > height()) { |
| return; |
| } |
| // TODO: Turn these into clamps. |
| if (src_rect.x + src_rect.width > src_bitmap.width() || |
| src_rect.y + src_rect.height > src_bitmap.height()) { |
| return; |
| } |
| if (dst_rect.x + dst_rect.width > width() || |
| dst_rect.y + dst_rect.height > height()) { |
| return; |
| } |
| |
| size_t copy_stride = src_rect.width * src_bitmap.pixelsize(); |
| size_t src_offset = |
| (src_bitmap.stride() * src_rect.y + src_rect.x) * src_bitmap.pixelsize(); |
| size_t dst_offset = (stride() * dst_rect.y + dst_rect.x) * pixelsize(); |
| uint8_t* src_buf = src_bitmap.buffer(); |
| uint8_t* dst_buf = buffer(); |
| |
| // Optimize for the case where we can do a single copy from src to dst. |
| if (dst_rect.width == width() && src_bitmap.stride() == stride()) { |
| copy(dst_buf + dst_offset, src_buf + src_offset, |
| copy_stride * dst_rect.height, format()); |
| return; |
| } |
| |
| for (uint32_t row = 0; row < src_rect.height; ++row) { |
| copy(dst_buf + dst_offset, src_buf + src_offset, copy_stride, format()); |
| src_offset += src_bitmap.stride() * src_bitmap.pixelsize(); |
| dst_offset += stride() * pixelsize(); |
| } |
| } |
| |
| } // namespace machina |