| // 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; |
| } |