blob: ceddd2ed728014ca94100e4b159a13b2a5760eaa [file] [log] [blame]
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "starboard/shared/directfb/blitter_internal.h"
#include "starboard/log.h"
#include "starboard/once.h"
namespace {
// Keep track of a global device registry that will be accessed by calls to
// create/destroy devices.
SbBlitterDeviceRegistry* s_device_registry = NULL;
SbOnceControl s_device_registry_once_control = SB_ONCE_INITIALIZER;
void EnsureDeviceRegistryInitialized() {
s_device_registry = new SbBlitterDeviceRegistry();
s_device_registry->default_device = NULL;
}
} // namespace
SbBlitterDeviceRegistry* GetBlitterDeviceRegistry() {
SbOnce(&s_device_registry_once_control, &EnsureDeviceRegistryInitialized);
return s_device_registry;
}
bool SetScissorRectangle(SbBlitterContext context, IDirectFBSurface* surface) {
// Setup the clipping region according to the context's stored scissor state.
DFBRegion clip_region;
clip_region.x1 = context->scissor.x;
clip_region.y1 = context->scissor.y;
clip_region.x2 = context->scissor.x + context->scissor.width;
clip_region.y2 = context->scissor.y + context->scissor.height;
if (surface->SetClip(surface, &clip_region) != DFB_OK) {
SB_DLOG(ERROR) << __FUNCTION__ << ": SetClip() failed.";
return false;
}
return true;
}
namespace {
SbBlitterColor PremultiplyColor(SbBlitterColor color) {
uint8_t alpha = SbBlitterAFromColor(color);
float alpha_float = alpha / 255.0f;
return SbBlitterColorFromRGBA(
static_cast<uint8_t>(SbBlitterRFromColor(color) * alpha_float),
static_cast<uint8_t>(SbBlitterGFromColor(color) * alpha_float),
static_cast<uint8_t>(SbBlitterBFromColor(color) * alpha_float), alpha);
}
} // namespace
bool SetDFBColor(IDirectFBSurface* surface, SbBlitterColor color) {
if (surface->SetColor(surface, SbBlitterRFromColor(color),
SbBlitterGFromColor(color), SbBlitterBFromColor(color),
SbBlitterAFromColor(color)) != DFB_OK) {
SB_DLOG(ERROR) << __FUNCTION__ << ": Error calling SetColor().";
return false;
}
return true;
}
bool SetupDFBSurfaceBlitStateFromBlitterContextState(
SbBlitterContext context,
SbBlitterSurface source,
IDirectFBSurface* surface) {
// Setup the DirectFB blending state on the surface as it is specified in
// the Blitter API context.
int blitting_flags = DSBLIT_NOFX;
if (source->info.format == kSbBlitterSurfaceFormatA8) {
// DirectFB A8 surfaces blit to (R, G, B, A) as (255, 255, 255, A), so in
// order to maintain a premultiplied alpha environment, we must indicate
// that the source color should be premultiplied as it is drawn.
blitting_flags |= DSBLIT_SRC_PREMULTIPLY;
}
if (context->blending_enabled) {
blitting_flags |= DSBLIT_BLEND_ALPHACHANNEL;
surface->SetPorterDuff(surface, DSPD_SRC_OVER);
} else {
surface->SetPorterDuff(surface, DSPD_SRC);
}
if (context->modulate_blits_with_color) {
blitting_flags |= DSBLIT_COLORIZE;
if (context->blending_enabled) {
blitting_flags |= DSBLIT_BLEND_COLORALPHA;
}
// If we have told DFB to premultiply for us, we don't need to manually
// premultiply the color.
SbBlitterColor color = (blitting_flags & DSBLIT_SRC_PREMULTIPLY)
? context->current_color
: PremultiplyColor(context->current_color);
if (!SetDFBColor(surface, color)) {
SB_DLOG(ERROR) << __FUNCTION__
<< ": Error calling SetUnpremultipliedColor().";
return false;
}
}
// Finally commit our DFB blitting flags to the surface.
if (surface->SetBlittingFlags(surface, static_cast<DFBSurfaceBlittingFlags>(
blitting_flags)) != DFB_OK) {
SB_DLOG(ERROR) << __FUNCTION__ << ": Error calling SetBlittingFlags().";
return false;
}
if (!SetScissorRectangle(context, surface)) {
SB_DLOG(ERROR) << __FUNCTION__ << ": Error calling SetScissorRectangle().";
return false;
}
return true;
}
bool SetupDFBSurfaceDrawStateFromBlitterContextState(
SbBlitterContext context,
IDirectFBSurface* surface) {
// Depending on the context blend state, set the DirectFB blend state flags
// on the current render target surface.
if (context->blending_enabled) {
surface->SetDrawingFlags(surface,
static_cast<DFBSurfaceDrawingFlags>(DSDRAW_BLEND));
surface->SetPorterDuff(surface, DSPD_SRC_OVER);
} else {
surface->SetDrawingFlags(surface, DSDRAW_NOFX);
surface->SetPorterDuff(surface, DSPD_SRC);
}
// Setup the rectangle fill color value as specified.
if (!SetDFBColor(surface, PremultiplyColor(context->current_color))) {
SB_DLOG(ERROR) << __FUNCTION__
<< ": Error calling SetUnpremultipliedColor().";
return false;
}
if (!SetScissorRectangle(context, surface)) {
SB_DLOG(ERROR) << __FUNCTION__ << ": Error calling SetScissorRectangle().";
return false;
}
return true;
}