view src/video/bwindow/SDL_sysyuv.cc @ 3485:e77a69aae239

Mason Wheeler to sdl I updated SDL, and suddenly my SDL frames stopped working. They'd "initialize" full of gibberish, and I couldn't render anything to them. After a bit of digging, I found a problem: the renderer initialization routine in my SDL frame code wasn't getting called anymore. procedure TSdlFrame.Paint; begin if SDL_SelectRenderer(FWindowID) = -1 then CreateRenderer; SDL_RenderPresent; end; function TSdlFrame.CreateRenderer: boolean; const pf: tagPIXELFORMATDESCRIPTOR = (nSize: sizeof(pf); nVersion: 1; dwFlags: PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER; iPixelType: PFD_TYPE_RGBA; cColorBits: 24; cAlphaBits: 8; iLayerType: PFD_MAIN_PLANE); RENDERERS: array[TRendererType] of AnsiString = ('software', 'gdi', 'opengl', 'd3d'); var pFormat: integer; begin if (SDL_SelectRenderer(FWindowID) = 0) then begin result := true; Exit; end; if FRendererType = rtOpenGL then begin pFormat := ChoosePixelFormat(canvas.Handle, @pf); if not SetPixelFormat(canvas.Handle, pFormat, @pf) then outputDebugString(PChar(SysErrorMessage(GetLastError))); if wglCreateContext(canvas.Handle) = 0 then outputDebugString(PChar(SysErrorMessage(GetLastError))); end; if (SDL_CreateRenderer(FWindowID, SDL_RendererIndex(RENDERERS[FRendererType]), [sdlrPresentFlip3, sdlrAccelerated]) = 0) then begin SDL_ShowWindow(FWindowID); assert(SDL_SetRenderDrawColor(0, 0, 0, 255) = 0); FFlags := SDL_GetWindowFlags(FWindowID); if assigned(FOnAvailable) then FOnAvailable(self); end else outputDebugString(pChar(format('SDL_CreateRenderer failed: %s', [sdl_GetError]))); result := SDL_SelectRenderer(FWindowID) = 0; end; This is a critical issue. The Paint method gets called when the control receives a WM_PAINT message from Windows. I can't create the renderer before then, or it will fail and cause trouble. And when I do create it, it needs to be created with certain parameters. So imagine my surprise when I started debugging into the DLL and found that SDL_SelectRenderer was trying to be "helpful" by creating the renderer for me if it didn't already exist! Now not only does my initialization code not get called, I end up with the wrong renderer and so things don't render as expected when I try to use the window.
author Sam Lantinga <slouken@libsdl.org>
date Tue, 24 Nov 2009 04:48:12 +0000
parents 99210400e8b9
children b530ef003506
line wrap: on
line source

/*
    SDL - Simple DirectMedia Layer
    Copyright (C) 1997-2009 Sam Lantinga

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

    Sam Lantinga
    slouken@libsdl.org
*/
#include "SDL_config.h"

/* This is the BeOS version of SDL YUV video overlays */

#include "SDL_video.h"
#include "SDL_sysyuv.h"
#include "../SDL_yuvfuncs.h"

extern "C"
{

/* The functions used to manipulate software video overlays */
    static struct private_yuvhwfuncs be_yuvfuncs = {
        BE_LockYUVOverlay,
        BE_UnlockYUVOverlay,
        BE_DisplayYUVOverlay,
        BE_FreeYUVOverlay
    };

    BBitmap *BE_GetOverlayBitmap(BRect bounds, color_space cs)
    {
        BBitmap *bbitmap;
        bbitmap = new BBitmap(bounds, B_BITMAP_WILL_OVERLAY, cs);
        if (!bbitmap || bbitmap->InitCheck() != B_OK) {
            delete bbitmap;
            return 0;
        }
        overlay_restrictions r;
        bbitmap->GetOverlayRestrictions(&r);
        uint32 width = bounds.IntegerWidth() + 1;
        uint32 height = bounds.IntegerHeight() + 1;
        uint32 width_padding = 0;
        uint32 height_padding = 0;
        if ((r.source.horizontal_alignment != 0) ||
            (r.source.vertical_alignment != 0)) {
            delete bbitmap;
            return 0;
        }
        if (r.source.width_alignment != 0) {
            uint32 aligned_width = r.source.width_alignment + 1;
            if (width % aligned_width > 0) {
                width_padding = aligned_width - width % aligned_width;
            }
        }
        if (r.source.height_alignment != 0) {
            uint32 aligned_height = r.source.height_alignment + 1;
            if (height % aligned_height > 0) {
                fprintf(stderr, "GetOverlayBitmap failed height alignment\n");
                fprintf(stderr, "- height = %lu, aligned_height = %lu\n",
                        height, aligned_height);
                delete bbitmap;
                return 0;
            }
        }
        if ((r.source.min_width > width) ||
            (r.source.min_height > height) ||
            (r.source.max_width < width) || (r.source.max_height < height)) {
            fprintf(stderr, "GetOverlayBitmap failed bounds tests\n");
            delete bbitmap;
            return 0;
        }
        if ((width_padding != 0) || (height_padding != 0)) {
            delete bbitmap;
            bounds.Set(bounds.left, bounds.top,
                       bounds.right + width_padding,
                       bounds.bottom + height_padding);
            bbitmap = new BBitmap(bounds, B_BITMAP_WILL_OVERLAY, cs);
            if (!bbitmap || bbitmap->InitCheck() != B_OK) {
                fprintf(stderr, "GetOverlayBitmap failed late\n");
                delete bbitmap;
                return 0;
            }
        }
        return bbitmap;
    }

// See <GraphicsDefs.h> [btw: Cb=U, Cr=V]
// See also http://www.fourcc.org/indexyuv.htm
    enum color_space convert_color_space(Uint32 format)
    {
        switch (format) {
        case SDL_YV12_OVERLAY:
            return B_YUV9;
        case SDL_IYUV_OVERLAY:
            return B_YUV12;
        case SDL_YUY2_OVERLAY:
            return B_YCbCr422;
        case SDL_UYVY_OVERLAY:
            return B_YUV422;
        case SDL_YVYU_OVERLAY: // not supported on beos?
            return B_NO_COLOR_SPACE;
        default:
            return B_NO_COLOR_SPACE;
        }
    }

// See SDL_video.h
    int count_planes(Uint32 format)
    {
        switch (format) {
        case SDL_YV12_OVERLAY:
        case SDL_IYUV_OVERLAY:
            return 3;
        case SDL_YUY2_OVERLAY:
        case SDL_UYVY_OVERLAY:
        case SDL_YVYU_OVERLAY:
            return 1;
        default:
            return 0;
        }
    }

    SDL_Overlay *BE_CreateYUVOverlay(_THIS, int width, int height,
                                     Uint32 format, SDL_Surface * display)
    {
        SDL_Overlay *overlay;
        struct private_yuvhwdata *hwdata;
        BBitmap *bbitmap;
        int planes;
        BRect bounds;
        color_space cs;

        /* find the appropriate BeOS colorspace descriptor */
        cs = convert_color_space(format);
        if (cs == B_NO_COLOR_SPACE) {
            return NULL;
        }

        /* count planes */
        planes = count_planes(format);
        if (planes == 0) {
            return NULL;
        }
        /* TODO: figure out planar modes, if anyone cares */
        if (planes == 3) {
            return NULL;
        }

        /* Create the overlay structure */
        overlay = (SDL_Overlay *) SDL_calloc(1, sizeof(SDL_Overlay));

        if (overlay == NULL) {
            SDL_OutOfMemory();
            return NULL;
        }

        /* Fill in the basic members */
        overlay->format = format;
        overlay->w = width;
        overlay->h = height;
        overlay->hwdata = NULL;

        /* Set up the YUV surface function structure */
        overlay->hwfuncs = &be_yuvfuncs;

        /* Create the pixel data and lookup tables */
        hwdata =
            (struct private_yuvhwdata *) SDL_calloc(1,
                                                    sizeof(struct
                                                           private_yuvhwdata));

        if (hwdata == NULL) {
            SDL_OutOfMemory();
            SDL_FreeYUVOverlay(overlay);
            return NULL;
        }

        overlay->hwdata = hwdata;
        overlay->hwdata->display = display;
        overlay->hwdata->bview = NULL;
        overlay->hwdata->bbitmap = NULL;
        overlay->hwdata->locked = 0;

        /* Create the BBitmap framebuffer */
        bounds.top = 0;
        bounds.left = 0;
        bounds.right = width - 1;
        bounds.bottom = height - 1;

        BView *bview =
            new BView(bounds, "overlay", B_FOLLOW_NONE, B_WILL_DRAW);
        if (!bview) {
            SDL_OutOfMemory();
            SDL_FreeYUVOverlay(overlay);
            return NULL;
        }
        overlay->hwdata->bview = bview;
        overlay->hwdata->first_display = true;
        bview->Hide();

        bbitmap = BE_GetOverlayBitmap(bounds, cs);
        if (!bbitmap) {
            overlay->hwdata->bbitmap = NULL;
            SDL_FreeYUVOverlay(overlay);
            return NULL;
        }
        overlay->hwdata->bbitmap = bbitmap;

        overlay->planes = planes;
        overlay->pitches =
            (Uint16 *) SDL_calloc(overlay->planes, sizeof(Uint16));
        overlay->pixels =
            (Uint8 **) SDL_calloc(overlay->planes, sizeof(Uint8 *));
        if (!overlay->pitches || !overlay->pixels) {
            SDL_OutOfMemory();
            SDL_FreeYUVOverlay(overlay);
            return (NULL);
        }

        overlay->pitches[0] = bbitmap->BytesPerRow();
        overlay->pixels[0] = (Uint8 *) bbitmap->Bits();
        overlay->hw_overlay = 1;

        if (SDL_Win->LockWithTimeout(1000000) != B_OK) {
            SDL_FreeYUVOverlay(overlay);
            return (NULL);
        }
        BView *view = SDL_Win->View();
        view->AddChild(bview);
        rgb_color key;
        bview->SetViewOverlay(bbitmap, bounds, bview->Bounds(), &key,
                              B_FOLLOW_ALL,
                              B_OVERLAY_FILTER_HORIZONTAL |
                              B_OVERLAY_FILTER_VERTICAL);
        bview->SetViewColor(key);
        bview->Flush();
        SDL_Win->Unlock();

        current_overlay = overlay;

        return overlay;
    }

    int BE_LockYUVOverlay(_THIS, SDL_Overlay * overlay)
    {
        if (overlay == NULL) {
            return 0;
        }

        overlay->hwdata->locked = 1;
        return 0;
    }

    void BE_UnlockYUVOverlay(_THIS, SDL_Overlay * overlay)
    {
        if (overlay == NULL) {
            return;
        }

        overlay->hwdata->locked = 0;
    }

    int BE_DisplayYUVOverlay(_THIS, SDL_Overlay * overlay, SDL_Rect * src,
                             SDL_Rect * dst)
    {
        if ((overlay == NULL) || (overlay->hwdata == NULL)
            || (overlay->hwdata->bview == NULL) || (SDL_Win->View() == NULL)) {
            return -1;
        }
        if (SDL_Win->LockWithTimeout(50000) != B_OK) {
            return 0;
        }
        BView *bview = overlay->hwdata->bview;
        if (SDL_Win->IsFullScreen()) {
            int left, top;
            SDL_Win->GetXYOffset(left, top);
            bview->MoveTo(left + dst->x, top + dst->y);
        } else {
            bview->MoveTo(dst->x, dst->y);
        }
        bview->ResizeTo(dst->w, dst->h);
        bview->Flush();
        if (overlay->hwdata->first_display) {
            bview->Show();
            overlay->hwdata->first_display = false;
        }
        SDL_Win->Unlock();

        return 0;
    }

    void BE_FreeYUVOverlay(_THIS, SDL_Overlay * overlay)
    {
        if (overlay == NULL) {
            return;
        }

        if (overlay->hwdata == NULL) {
            return;
        }

        current_overlay = NULL;

        delete overlay->hwdata->bbitmap;

        SDL_free(overlay->hwdata);
    }

};                              // extern "C"

/* vi: set ts=4 sw=4 expandtab: */