blob: 21a6e8e615b812772ce6e091f433ee35740b4cbf [file] [log] [blame]
// 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