blitter.cpp revision 24e27201b1438d88569467f104a0e3cb1df190ed
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk/* $Id$ */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk/** @file
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Blitter API implementation
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk/*
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Copyright (C) 2013 Oracle Corporation
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk *
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * This file is part of VirtualBox Open Source Edition (OSE), as
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * available from http://www.virtualbox.org. This file is free software;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * you can redistribute it and/or modify it under the terms of the GNU
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * General Public License (GPL) as published by the Free Software
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Foundation, in version 2 as it comes in the "COPYING" file of the
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk#include "cr_blitter.h"
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk#include "cr_spu.h"
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk#include "chromium.h"
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk#include "cr_error.h"
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk#include "cr_net.h"
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk#include "cr_rand.h"
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk#include "cr_mem.h"
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk#include "cr_string.h"
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk#include <iprt/cdefs.h>
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk#include <iprt/types.h>
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk#include <iprt/mem.h>
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk/* @param pCtxBase - contains the blitter context info. Its value is treated differently depending on the fCreateNewCtx value
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * @param fCreateNewCtx - if true - the pCtxBase must NOT be NULL. its visualBits is used as a visual bits info for the new context,
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * its id field is used to specified the shared context id to be used for blitter context.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * The id can be null to specify no shared context is needed
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * if false - if pCtxBase is NOT null AND its id field is NOT null -
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * specified the blitter context to be used
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * blitter treats it as if it has default ogl state.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * otherwise -
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * the blitter works in a "no-context" mode, i.e. a caller is responsible
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * to making a proper context current before calling the blitter.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Note that BltEnter/Leave MUST still be called, but the proper context
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * must be set before doing BltEnter, and ResoreContext info is ignored in that case.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Also note that blitter caches the current window info, and assumes the current context's values are preserved
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * wrt that window before the calls, so if one uses different contexts for one blitter,
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * the blitter current window values must be explicitly reset by doing CrBltMuralSetCurrentInfo(pBlitter, NULL)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * @param fForceDrawBlt - if true - forces the blitter to always use glDrawXxx-based blits even if GL_EXT_framebuffer_blit.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * This is needed because BlitFramebufferEXT is known to be often buggy, and glDrawXxx-based blits appear to be more reliable
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenkVBOXBLITTERDECL(int) CrBltInit(PCR_BLITTER pBlitter, const CR_BLITTER_CONTEXT *pCtxBase, bool fCreateNewCtx, bool fForceDrawBlt, const CR_GLSL_CACHE *pShaders, SPUDispatchTable *pDispatch)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk{
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (pCtxBase && pCtxBase->Base.id < 0)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk crWarning("Default share context not initialized!");
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return VERR_INVALID_PARAMETER;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (!pCtxBase && fCreateNewCtx)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk crWarning("pCtxBase is zero while fCreateNewCtx is set!");
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return VERR_INVALID_PARAMETER;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk memset(pBlitter, 0, sizeof (*pBlitter));
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBlitter->pDispatch = pDispatch;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (pCtxBase)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBlitter->CtxInfo = *pCtxBase;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBlitter->Flags.ForceDrawBlit = fForceDrawBlt;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (fCreateNewCtx)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBlitter->CtxInfo.Base.id = pDispatch->CreateContext("", pCtxBase->Base.visualBits, pCtxBase->Base.id);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (!pBlitter->CtxInfo.Base.id)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk memset(pBlitter, 0, sizeof (*pBlitter));
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk crWarning("CreateContext failed!");
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return VERR_GENERAL_FAILURE;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBlitter->Flags.CtxCreated = 1;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (pShaders)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBlitter->pGlslCache = pShaders;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBlitter->Flags.ShadersGloal = 1;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk else
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk CrGlslInit(&pBlitter->LocalGlslCache, pDispatch);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBlitter->pGlslCache = &pBlitter->LocalGlslCache;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return VINF_SUCCESS;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk}
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenkVBOXBLITTERDECL(int) CrBltCleanup(PCR_BLITTER pBlitter)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk{
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (CrBltIsEntered(pBlitter))
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk crWarning("CrBltBlitTexTex: blitter is entered");
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return VERR_INVALID_STATE;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (pBlitter->Flags.ShadersGloal || !CrGlslNeedsCleanup(&pBlitter->LocalGlslCache))
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return VINF_SUCCESS;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk int rc = CrBltEnter(pBlitter);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (!RT_SUCCESS(rc))
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk crWarning("CrBltEnter failed, rc %d", rc);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return rc;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk CrGlslCleanup(&pBlitter->LocalGlslCache);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk CrBltLeave(pBlitter);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return VINF_SUCCESS;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk}
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenkvoid CrBltTerm(PCR_BLITTER pBlitter)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk{
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (pBlitter->Flags.CtxCreated)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBlitter->pDispatch->DestroyContext(pBlitter->CtxInfo.Base.id);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk memset(pBlitter, 0, sizeof (*pBlitter));
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk}
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenkint CrBltMuralSetCurrentInfo(PCR_BLITTER pBlitter, const CR_BLITTER_WINDOW *pMural)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk{
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (pMural)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (!memcmp(&pBlitter->CurrentMural, pMural, sizeof (pBlitter->CurrentMural)))
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return VINF_SUCCESS;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk memcpy(&pBlitter->CurrentMural, pMural, sizeof (pBlitter->CurrentMural));
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk else
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (CrBltIsEntered(pBlitter))
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk crWarning("can not set null mural for entered bleater");
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return VERR_INVALID_STATE;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (!pBlitter->CurrentMural.Base.id)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return VINF_SUCCESS;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBlitter->CurrentMural.Base.id = 0;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBlitter->Flags.CurrentMuralChanged = 1;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (!CrBltIsEntered(pBlitter))
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return VINF_SUCCESS;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk else if (!pBlitter->CtxInfo.Base.id)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk crWarning("setting current mural for entered no-context blitter");
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return VERR_INVALID_STATE;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk crWarning("changing mural for entered blitter, is is somewhat expected?");
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBlitter->pDispatch->Flush();
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBlitter->pDispatch->MakeCurrent(pMural->Base.id, pBlitter->i32MakeCurrentUserData, pBlitter->CtxInfo.Base.id);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return VINF_SUCCESS;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk}
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenkstatic DECLCALLBACK(int) crBltBlitTexBufImplFbo(PCR_BLITTER pBlitter, const VBOXVR_TEXTURE *pSrc, const RTRECT *paSrcRect, const RTRECTSIZE *pDstSize, const RTRECT *paDstRect, uint32_t cRects, uint32_t fFlags)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk{
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk GLenum filter = CRBLT_FILTER_FROM_FLAGS(fFlags);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBlitter->pDispatch->BindFramebufferEXT(GL_READ_FRAMEBUFFER, pBlitter->idFBO);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBlitter->pDispatch->FramebufferTexture2DEXT(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, pSrc->target, pSrc->hwid, 0);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBlitter->pDispatch->ReadBuffer(GL_COLOR_ATTACHMENT0);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk for (uint32_t i = 0; i < cRects; ++i)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk const RTRECT * pSrcRect = &paSrcRect[i];
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk const RTRECT * pDstRect = &paDstRect[i];
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk int32_t srcY1;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk int32_t srcY2;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk int32_t dstY1;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk int32_t dstY2;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk int32_t srcX1 = pSrcRect->xLeft;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk int32_t srcX2 = pSrcRect->xRight;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk int32_t dstX1 = pDstRect->xLeft;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk int32_t dstX2 = pDstRect->xRight;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (CRBLT_F_INVERT_SRC_YCOORDS & fFlags)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk srcY1 = pSrc->height - pSrcRect->yTop;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk srcY2 = pSrc->height - pSrcRect->yBottom;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk else
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk srcY1 = pSrcRect->yTop;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk srcY2 = pSrcRect->yBottom;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (CRBLT_F_INVERT_DST_YCOORDS & fFlags)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk dstY1 = pDstSize->cy - pDstRect->yTop;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk dstY2 = pDstSize->cy - pDstRect->yBottom;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk else
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk dstY1 = pDstRect->yTop;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk dstY2 = pDstRect->yBottom;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (srcY1 > srcY2)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (dstY1 > dstY2)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /* use srcY1 < srcY2 && dstY1 < dstY2 whenever possible to avoid GPU driver bugs */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk int32_t tmp = srcY1;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk srcY1 = srcY2;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk srcY2 = tmp;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk tmp = dstY1;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk dstY1 = dstY2;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk dstY2 = tmp;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (srcX1 > srcX2)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (dstX1 > dstX2)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /* use srcX1 < srcX2 && dstX1 < dstX2 whenever possible to avoid GPU driver bugs */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk int32_t tmp = srcX1;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk srcX1 = srcX2;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk srcX2 = tmp;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk tmp = dstX1;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk dstX1 = dstX2;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk dstX2 = tmp;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBlitter->pDispatch->BlitFramebufferEXT(srcX1, srcY1, srcX2, srcY2,
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk dstX1, dstY1, dstX2, dstY2,
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk GL_COLOR_BUFFER_BIT, filter);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return VINF_SUCCESS;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk}
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk/* GL_TRIANGLE_FAN */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenkDECLINLINE(GLfloat*) crBltVtRectTFNormalized(const RTRECT *pRect, uint32_t normalX, uint32_t normalY, GLfloat* pBuff, uint32_t height)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk{
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /* going ccw:
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * 1. (left;top) 4. (right;top)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * | ^
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * > |
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * 2. (left;bottom) -> 3. (right;bottom) */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /* xLeft yTop */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBuff[0] = ((float)pRect->xLeft)/((float)normalX);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBuff[1] = ((float)(height ? height - pRect->yTop : pRect->yTop))/((float)normalY);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /* xLeft yBottom */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBuff[2] = pBuff[0];
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBuff[3] = ((float)(height ? height - pRect->yBottom : pRect->yBottom))/((float)normalY);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /* xRight yBottom */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBuff[4] = ((float)pRect->xRight)/((float)normalX);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBuff[5] = pBuff[3];
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /* xRight yTop */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBuff[6] = pBuff[4];
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBuff[7] = pBuff[1];
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return &pBuff[8];
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk}
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenkDECLINLINE(GLfloat*) crBltVtRectsTFNormalized(const RTRECT *paRects, uint32_t cRects, uint32_t normalX, uint32_t normalY, GLfloat* pBuff, uint32_t height)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk{
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk for (uint32_t i = 0; i < cRects; ++i)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBuff = crBltVtRectTFNormalized(&paRects[i], normalX, normalY, pBuff, height);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return pBuff;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk}
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenkDECLINLINE(GLint*) crBltVtRectTF(const RTRECT *pRect, uint32_t normalX, uint32_t normalY, GLint* pBuff, uint32_t height)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk{
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /* xLeft yTop */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBuff[0] = pRect->xLeft;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBuff[1] = height ? height - pRect->yTop : pRect->yTop;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /* xLeft yBottom */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBuff[2] = pBuff[0];
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBuff[3] = height ? height - pRect->yBottom : pRect->yBottom;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /* xRight yBottom */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBuff[4] = pRect->xRight;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBuff[5] = pBuff[3];
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /* xRight yTop */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBuff[6] = pBuff[4];
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBuff[7] = pBuff[1];
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return &pBuff[8];
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk}
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenkDECLINLINE(GLubyte*) crBltVtFillRectIndicies(GLubyte *pIndex, GLubyte *piBase)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk{
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk GLubyte iBase = *piBase;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /* triangle 1 */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pIndex[0] = iBase;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pIndex[1] = iBase + 1;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pIndex[2] = iBase + 2;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /* triangle 2 */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pIndex[3] = iBase;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pIndex[4] = iBase + 2;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pIndex[5] = iBase + 3;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk *piBase = iBase + 4;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return pIndex + 6;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk}
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk/* Indexed GL_TRIANGLES */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenkDECLINLINE(GLfloat*) crBltVtRectITNormalized(const RTRECT *pRect, uint32_t normalX, uint32_t normalY, GLfloat* pBuff, uint32_t height)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk{
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk GLfloat* ret = crBltVtRectTFNormalized(pRect, normalX, normalY, pBuff, height);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return ret;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk}
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenkDECLINLINE(GLint*) crBltVtRectIT(RTRECT *pRect, uint32_t normalX, uint32_t normalY, GLint* pBuff, GLubyte **ppIndex, GLubyte *piBase, uint32_t height)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk{
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk GLint* ret = crBltVtRectTF(pRect, normalX, normalY, pBuff, height);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (ppIndex)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk *ppIndex = crBltVtFillRectIndicies(*ppIndex, piBase);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return ret;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk}
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenkDECLINLINE(GLuint) crBltVtGetNumVerticiesTF(GLuint cRects)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk{
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return cRects * 4;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk}
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk#define crBltVtGetNumVerticiesIT crBltVtGetNumVerticiesTF
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenkDECLINLINE(GLuint) crBltVtGetNumIndiciesIT(GLuint cRects)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk{
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return 6 * cRects;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk}
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenkstatic GLfloat* crBltVtRectsITNormalized(const RTRECT *paRects, uint32_t cRects, uint32_t normalX, uint32_t normalY, GLfloat* pBuff, GLubyte **ppIndex, GLubyte *piBase, uint32_t height)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk{
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk uint32_t i;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk for (i = 0; i < cRects; ++i)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBuff = crBltVtRectITNormalized(&paRects[i], normalX, normalY, pBuff, height);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (ppIndex)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk GLubyte *pIndex = (GLubyte*)pBuff;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk *ppIndex = pIndex;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk for (i = 0; i < cRects; ++i)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pIndex = crBltVtFillRectIndicies(pIndex, piBase);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBuff = (GLfloat*)pIndex;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return pBuff;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk}
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenkstatic void* crBltBufGet(PCR_BLITTER_BUFFER pBuffer, GLuint cbBuffer)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk{
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (pBuffer->cbBuffer < cbBuffer)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (pBuffer->pvBuffer)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk RTMemFree(pBuffer->pvBuffer);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk#ifndef DEBUG_misha
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /* debugging: ensure we calculate proper buffer size */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk cbBuffer += 16;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk#endif
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBuffer->pvBuffer = RTMemAlloc(cbBuffer);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (pBuffer->pvBuffer)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBuffer->cbBuffer = cbBuffer;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk else
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk crWarning("failed to allocate buffer of size %d", cbBuffer);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBuffer->cbBuffer = 0;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return pBuffer->pvBuffer;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk}
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenkstatic void crBltCheckSetupViewport(PCR_BLITTER pBlitter, const RTRECTSIZE *pDstSize, bool fFBODraw)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk{
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk bool fUpdateViewport = pBlitter->Flags.CurrentMuralChanged;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (pBlitter->CurrentSetSize.cx != pDstSize->cx
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk || pBlitter->CurrentSetSize.cy != pDstSize->cy)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBlitter->CurrentSetSize = *pDstSize;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBlitter->pDispatch->MatrixMode(GL_PROJECTION);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBlitter->pDispatch->LoadIdentity();
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBlitter->pDispatch->Ortho(0, pDstSize->cx, 0, pDstSize->cy, -1, 1);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk fUpdateViewport = true;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (fUpdateViewport)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBlitter->pDispatch->Viewport(0, 0, pBlitter->CurrentSetSize.cx, pBlitter->CurrentSetSize.cy);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBlitter->Flags.CurrentMuralChanged = 0;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk pBlitter->Flags.LastWasFBODraw = fFBODraw;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk}
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenkstatic DECLCALLBACK(int) crBltBlitTexBufImplDraw2D(PCR_BLITTER pBlitter, const VBOXVR_TEXTURE *pSrc, const RTRECT *paSrcRect, const RTRECTSIZE *pDstSize, const RTRECT *paDstRect, uint32_t cRects, uint32_t fFlags)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk{
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk GLuint normalX, normalY;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk uint32_t srcHeight = (fFlags & CRBLT_F_INVERT_SRC_YCOORDS) ? pSrc->height : 0;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk uint32_t dstHeight = (fFlags & CRBLT_F_INVERT_DST_YCOORDS) ? pDstSize->cy : 0;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk switch (pSrc->target)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk case GL_TEXTURE_2D:
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk normalX = pSrc->width;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk normalY = pSrc->height;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk break;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk case GL_TEXTURE_RECTANGLE_ARB:
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk normalX = 1;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk normalY = 1;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk break;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk default:
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk crWarning("Unsupported texture target 0x%x", pSrc->target);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return VERR_INVALID_PARAMETER;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk Assert(pSrc->hwid);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
pBlitter->pDispatch->BindTexture(pSrc->target, pSrc->hwid);
if (cRects == 1)
{
/* just optimization to draw a single rect with GL_TRIANGLE_FAN */
GLfloat *pVerticies;
GLfloat *pTexCoords;
GLuint cElements = crBltVtGetNumVerticiesTF(cRects);
pVerticies = (GLfloat*)crBltBufGet(&pBlitter->Verticies, cElements * 2 * 2 * sizeof (*pVerticies));
pTexCoords = crBltVtRectsTFNormalized(paDstRect, cRects, 1, 1, pVerticies, dstHeight);
crBltVtRectsTFNormalized(paSrcRect, cRects, normalX, normalY, pTexCoords, srcHeight);
pBlitter->pDispatch->EnableClientState(GL_VERTEX_ARRAY);
pBlitter->pDispatch->VertexPointer(2, GL_FLOAT, 0, pVerticies);
pBlitter->pDispatch->EnableClientState(GL_TEXTURE_COORD_ARRAY);
pBlitter->pDispatch->TexCoordPointer(2, GL_FLOAT, 0, pTexCoords);
pBlitter->pDispatch->Enable(pSrc->target);
pBlitter->pDispatch->DrawArrays(GL_TRIANGLE_FAN, 0, cElements);
pBlitter->pDispatch->Disable(pSrc->target);
pBlitter->pDispatch->DisableClientState(GL_TEXTURE_COORD_ARRAY);
pBlitter->pDispatch->DisableClientState(GL_VERTEX_ARRAY);
}
else
{
GLfloat *pVerticies;
GLfloat *pTexCoords;
GLubyte *pIndicies;
GLuint cElements = crBltVtGetNumVerticiesIT(cRects);
GLuint cIndicies = crBltVtGetNumIndiciesIT(cRects);
GLubyte iIdxBase = 0;
pVerticies = (GLfloat*)crBltBufGet(&pBlitter->Verticies, cElements * 2 * 2 * sizeof (*pVerticies) + cIndicies * sizeof (*pIndicies));
pTexCoords = crBltVtRectsITNormalized(paDstRect, cRects, 1, 1, pVerticies, &pIndicies, &iIdxBase, dstHeight);
crBltVtRectsITNormalized(paSrcRect, cRects, normalX, normalY, pTexCoords, NULL, NULL, srcHeight);
pBlitter->pDispatch->EnableClientState(GL_VERTEX_ARRAY);
pBlitter->pDispatch->VertexPointer(2, GL_FLOAT, 0, pVerticies);
pBlitter->pDispatch->EnableClientState(GL_TEXTURE_COORD_ARRAY);
pBlitter->pDispatch->TexCoordPointer(2, GL_FLOAT, 0, pTexCoords);
pBlitter->pDispatch->Enable(pSrc->target);
pBlitter->pDispatch->DrawElements(GL_TRIANGLES, cIndicies, GL_UNSIGNED_BYTE, pIndicies);
pBlitter->pDispatch->Disable(pSrc->target);
pBlitter->pDispatch->DisableClientState(GL_TEXTURE_COORD_ARRAY);
pBlitter->pDispatch->DisableClientState(GL_VERTEX_ARRAY);
}
pBlitter->pDispatch->BindTexture(pSrc->target, 0);
return VINF_SUCCESS;
}
static int crBltInitOnMakeCurent(PCR_BLITTER pBlitter)
{
const char * pszExtension = (const char*)pBlitter->pDispatch->GetString(GL_EXTENSIONS);
if (crStrstr(pszExtension, "GL_EXT_framebuffer_object"))
{
pBlitter->Flags.SupportsFBO = 1;
pBlitter->pDispatch->GenFramebuffersEXT(1, &pBlitter->idFBO);
Assert(pBlitter->idFBO);
}
else
crWarning("GL_EXT_framebuffer_object not supported, blitter can only blit to window");
if (crStrstr(pszExtension, "GL_ARB_pixel_buffer_object"))
pBlitter->Flags.SupportsPBO = 1;
else
crWarning("GL_ARB_pixel_buffer_object not supported");
/* BlitFramebuffer seems to be buggy on Intel,
* try always glDrawXxx for now */
if (!pBlitter->Flags.ForceDrawBlit && crStrstr(pszExtension, "GL_EXT_framebuffer_blit"))
{
pBlitter->pfnBlt = crBltBlitTexBufImplFbo;
}
else
{
// crWarning("GL_EXT_framebuffer_blit not supported, will use Draw functions for blitting, which might be less efficient");
pBlitter->pfnBlt = crBltBlitTexBufImplDraw2D;
}
/* defaults. but just in case */
pBlitter->pDispatch->MatrixMode(GL_TEXTURE);
pBlitter->pDispatch->LoadIdentity();
pBlitter->pDispatch->MatrixMode(GL_MODELVIEW);
pBlitter->pDispatch->LoadIdentity();
return VINF_SUCCESS;
}
void CrBltLeave(PCR_BLITTER pBlitter)
{
if (!CrBltIsEntered(pBlitter))
{
WARN(("CrBltLeave: blitter not entered"));
return;
}
if (pBlitter->Flags.SupportsFBO)
{
pBlitter->pDispatch->BindFramebufferEXT(GL_FRAMEBUFFER, 0);
pBlitter->pDispatch->DrawBuffer(GL_BACK);
pBlitter->pDispatch->ReadBuffer(GL_BACK);
}
pBlitter->pDispatch->Flush();
if (pBlitter->CtxInfo.Base.id)
pBlitter->pDispatch->MakeCurrent(0, 0, 0);
pBlitter->Flags.Entered = 0;
}
int CrBltEnter(PCR_BLITTER pBlitter)
{
if (!pBlitter->CurrentMural.Base.id && pBlitter->CtxInfo.Base.id)
{
WARN(("current mural not initialized!"));
return VERR_INVALID_STATE;
}
if (CrBltIsEntered(pBlitter))
{
WARN(("blitter is entered already!"));
return VERR_INVALID_STATE;
}
if (pBlitter->CurrentMural.Base.id) /* <- pBlitter->CurrentMural.Base.id can be null if the blitter is in a "no-context" mode (see comments to BltInit for detail)*/
{
pBlitter->pDispatch->MakeCurrent(pBlitter->CurrentMural.Base.id, pBlitter->i32MakeCurrentUserData, pBlitter->CtxInfo.Base.id);
}
pBlitter->Flags.Entered = 1;
if (pBlitter->Flags.Initialized)
return VINF_SUCCESS;
int rc = crBltInitOnMakeCurent(pBlitter);
if (RT_SUCCESS(rc))
{
pBlitter->Flags.Initialized = 1;
return VINF_SUCCESS;
}
WARN(("crBltInitOnMakeCurent failed, rc %d", rc));
CrBltLeave(pBlitter);
return rc;
}
static void crBltBlitTexBuf(PCR_BLITTER pBlitter, const VBOXVR_TEXTURE *pSrc, const RTRECT *paSrcRects, GLenum enmDstBuff, const RTRECTSIZE *pDstSize, const RTRECT *paDstRects, uint32_t cRects, uint32_t fFlags)
{
pBlitter->pDispatch->DrawBuffer(enmDstBuff);
crBltCheckSetupViewport(pBlitter, pDstSize, enmDstBuff == GL_DRAW_FRAMEBUFFER);
if (!(fFlags & CRBLT_F_NOALPHA))
pBlitter->pfnBlt(pBlitter, pSrc, paSrcRects, pDstSize, paDstRects, cRects, fFlags);
else
{
int rc = pBlitter->Flags.ShadersGloal ?
CrGlslProgUseNoAlpha(pBlitter->pGlslCache, pSrc->target)
:
CrGlslProgUseGenNoAlpha(&pBlitter->LocalGlslCache, pSrc->target);
if (!RT_SUCCESS(rc))
{
crWarning("Failed to use no-alpha program rc %d!, falling back to default blit", rc);
pBlitter->pfnBlt(pBlitter, pSrc, paSrcRects, pDstSize, paDstRects, cRects, fFlags);
return;
}
/* since we use shaders, we need to use draw commands rather than framebuffer blits.
* force using draw-based blitting */
crBltBlitTexBufImplDraw2D(pBlitter, pSrc, paSrcRects, pDstSize, paDstRects, cRects, fFlags);
Assert(pBlitter->Flags.ShadersGloal || &pBlitter->LocalGlslCache == pBlitter->pGlslCache);
CrGlslProgClear(pBlitter->pGlslCache);
}
}
void CrBltCheckUpdateViewport(PCR_BLITTER pBlitter)
{
RTRECTSIZE DstSize = {pBlitter->CurrentMural.width, pBlitter->CurrentMural.height};
crBltCheckSetupViewport(pBlitter, &DstSize, false);
}
void CrBltBlitTexMural(PCR_BLITTER pBlitter, bool fBb, const VBOXVR_TEXTURE *pSrc, const RTRECT *paSrcRects, const RTRECT *paDstRects, uint32_t cRects, uint32_t fFlags)
{
if (!CrBltIsEntered(pBlitter))
{
crWarning("CrBltBlitTexMural: blitter not entered");
return;
}
RTRECTSIZE DstSize = {pBlitter->CurrentMural.width, pBlitter->CurrentMural.height};
pBlitter->pDispatch->BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, 0);
crBltBlitTexBuf(pBlitter, pSrc, paSrcRects, fBb ? GL_BACK : GL_FRONT, &DstSize, paDstRects, cRects, fFlags);
}
void CrBltBlitTexTex(PCR_BLITTER pBlitter, const VBOXVR_TEXTURE *pSrc, const RTRECT *pSrcRect, const VBOXVR_TEXTURE *pDst, const RTRECT *pDstRect, uint32_t cRects, uint32_t fFlags)
{
if (!CrBltIsEntered(pBlitter))
{
crWarning("CrBltBlitTexTex: blitter not entered");
return;
}
RTRECTSIZE DstSize = {(uint32_t)pDst->width, (uint32_t)pDst->height};
pBlitter->pDispatch->BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, pBlitter->idFBO);
/* TODO: mag/min filters ? */
pBlitter->pDispatch->FramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, pDst->target, pDst->hwid, 0);
// pBlitter->pDispatch->FramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
// pBlitter->pDispatch->FramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
crBltBlitTexBuf(pBlitter, pSrc, pSrcRect, GL_DRAW_FRAMEBUFFER, &DstSize, pDstRect, cRects, fFlags);
pBlitter->pDispatch->FramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, pDst->target, 0, 0);
}
void CrBltPresent(PCR_BLITTER pBlitter)
{
if (!CrBltIsEntered(pBlitter))
{
crWarning("CrBltPresent: blitter not entered");
return;
}
if (pBlitter->CtxInfo.Base.visualBits & CR_DOUBLE_BIT)
pBlitter->pDispatch->SwapBuffers(pBlitter->CurrentMural.Base.id, 0);
else
pBlitter->pDispatch->Flush();
}
static int crBltImgInitBaseForTex(const VBOXVR_TEXTURE *pSrc, CR_BLITTER_IMG *pDst, GLenum enmFormat)
{
memset(pDst, 0, sizeof (*pDst));
if (enmFormat != GL_RGBA
&& enmFormat != GL_BGRA)
{
crWarning("unsupported format 0x%x", enmFormat);
return VERR_NOT_IMPLEMENTED;
}
uint32_t bpp = 32;
uint32_t pitch = ((bpp * pSrc->width) + 7) >> 3;
uint32_t cbData = pitch * pSrc->height;
pDst->cbData = cbData;
pDst->enmFormat = enmFormat;
pDst->width = pSrc->width;
pDst->height = pSrc->height;
pDst->bpp = bpp;
pDst->pitch = pitch;
return VINF_SUCCESS;
}
static int crBltImgCreateForTex(const VBOXVR_TEXTURE *pSrc, CR_BLITTER_IMG *pDst, GLenum enmFormat)
{
int rc = crBltImgInitBaseForTex(pSrc, pDst, enmFormat);
if (!RT_SUCCESS(rc))
{
crWarning("crBltImgInitBaseForTex failed rc %d", rc);
return rc;
}
uint32_t cbData = pDst->cbData;
pDst->pvData = RTMemAllocZ(cbData);
if (!pDst->pvData)
{
crWarning("RTMemAlloc failed");
return VERR_NO_MEMORY;
}
#ifdef DEBUG_misha
{
char *pTmp = (char*)pDst->pvData;
for (uint32_t i = 0; i < cbData; ++i)
{
pTmp[i] = (char)((1 << i) % 255);
}
}
#endif
return VINF_SUCCESS;
}
VBOXBLITTERDECL(int) CrBltImgGetTex(PCR_BLITTER pBlitter, const VBOXVR_TEXTURE *pSrc, GLenum enmFormat, CR_BLITTER_IMG *pDst)
{
if (!CrBltIsEntered(pBlitter))
{
crWarning("CrBltImgGetTex: blitter not entered");
return VERR_INVALID_STATE;
}
int rc = crBltImgCreateForTex(pSrc, pDst, enmFormat);
if (!RT_SUCCESS(rc))
{
crWarning("crBltImgCreateForTex failed, rc %d", rc);
return rc;
}
pBlitter->pDispatch->BindTexture(pSrc->target, pSrc->hwid);
#ifdef DEBUG_misha
{
GLint width = 0, height = 0, depth = 0;
pBlitter->pDispatch->GetTexLevelParameteriv(pSrc->target, 0, GL_TEXTURE_WIDTH, &width);
pBlitter->pDispatch->GetTexLevelParameteriv(pSrc->target, 0, GL_TEXTURE_HEIGHT, &height);
pBlitter->pDispatch->GetTexLevelParameteriv(pSrc->target, 0, GL_TEXTURE_DEPTH, &depth);
Assert(width == pSrc->width);
Assert(height == pSrc->height);
// Assert(depth == pSrc->depth);
}
#endif
pBlitter->pDispatch->GetTexImage(pSrc->target, 0, enmFormat, GL_UNSIGNED_BYTE, pDst->pvData);
pBlitter->pDispatch->BindTexture(pSrc->target, 0);
return VINF_SUCCESS;
}
VBOXBLITTERDECL(int) CrBltImgGetMural(PCR_BLITTER pBlitter, bool fBb, CR_BLITTER_IMG *pDst)
{
if (!CrBltIsEntered(pBlitter))
{
crWarning("CrBltImgGetMural: blitter not entered");
return VERR_INVALID_STATE;
}
crWarning("NOT IMPLEMENTED");
return VERR_NOT_IMPLEMENTED;
}
VBOXBLITTERDECL(void) CrBltImgFree(PCR_BLITTER pBlitter, CR_BLITTER_IMG *pDst)
{
if (!CrBltIsEntered(pBlitter))
{
crWarning("CrBltImgFree: blitter not entered");
return;
}
if (pDst->pvData)
{
RTMemFree(pDst->pvData);
pDst->pvData = NULL;
}
}
VBOXBLITTERDECL(bool) CrGlslIsSupported(CR_GLSL_CACHE *pCache)
{
if (pCache->iGlVersion == 0)
{
const char * pszStr = (const char*)pCache->pDispatch->GetString(GL_VERSION);
pCache->iGlVersion = crStrParseGlVersion(pszStr);
if (pCache->iGlVersion <= 0)
{
crWarning("crStrParseGlVersion returned %d", pCache->iGlVersion);
pCache->iGlVersion = -1;
}
}
if (pCache->iGlVersion >= CR_GLVERSION_COMPOSE(2, 0, 0))
return true;
crWarning("GLSL unsuported, gl version %d", pCache->iGlVersion);
/* @todo: we could also check for GL_ARB_shader_objects and GL_ARB_fragment_shader,
* but seems like chromium does not support properly gl*Object versions of shader functions used with those extensions */
return false;
}
#define CR_GLSL_STR_V_120 "#version 120\n"
#define CR_GLSL_STR_EXT_TR "#extension GL_ARB_texture_rectangle : enable\n"
#define CR_GLSL_STR_2D "2D"
#define CR_GLSL_STR_2DRECT "2DRect"
#define CR_GLSL_PATTERN_FS_NOALPHA(_ver, _ext, _tex) \
_ver \
_ext \
"uniform sampler" _tex " sampler0;\n" \
"void main()\n" \
"{\n" \
"vec2 srcCoord = vec2(gl_TexCoord[0]);\n" \
"gl_FragData[0].xyz = (texture" _tex "(sampler0, srcCoord).xyz);\n" \
"gl_FragData[0].w = 1.0;\n" \
"}\n"
static const char* crGlslGetFsStringNoAlpha(CR_GLSL_CACHE *pCache, GLenum enmTexTarget)
{
if (!CrGlslIsSupported(pCache))
{
crWarning("CrGlslIsSupported is false");
return NULL;
}
if (pCache->iGlVersion >= CR_GLVERSION_COMPOSE(2, 1, 0))
{
if (enmTexTarget == GL_TEXTURE_2D)
return CR_GLSL_PATTERN_FS_NOALPHA(CR_GLSL_STR_V_120, "", CR_GLSL_STR_2D);
else if (enmTexTarget == GL_TEXTURE_RECTANGLE_ARB)
return CR_GLSL_PATTERN_FS_NOALPHA(CR_GLSL_STR_V_120, CR_GLSL_STR_EXT_TR, CR_GLSL_STR_2DRECT);
crWarning("invalid enmTexTarget %#x", enmTexTarget);
return NULL;
}
else if (pCache->iGlVersion >= CR_GLVERSION_COMPOSE(2, 0, 0))
{
if (enmTexTarget == GL_TEXTURE_2D)
return CR_GLSL_PATTERN_FS_NOALPHA("", "", CR_GLSL_STR_2D);
else if (enmTexTarget == GL_TEXTURE_RECTANGLE_ARB)
return CR_GLSL_PATTERN_FS_NOALPHA("", CR_GLSL_STR_EXT_TR, CR_GLSL_STR_2DRECT);
crWarning("invalid enmTexTarget %#x", enmTexTarget);
return NULL;
}
crError("crGlslGetFsStringNoAlpha: we should not be here!");
return NULL;
}
static int crGlslProgGenNoAlpha(CR_GLSL_CACHE *pCache, GLenum enmTexTarget, GLuint *puiProgram)
{
*puiProgram = 0;
const char*pStrFsShader = crGlslGetFsStringNoAlpha(pCache, enmTexTarget);
if (!pStrFsShader)
{
crWarning("crGlslGetFsStringNoAlpha failed");
return VERR_NOT_SUPPORTED;
}
int rc = VINF_SUCCESS;
GLchar * pBuf = NULL;
GLuint uiProgram = 0;
GLint iUniform = -1;
GLuint uiShader = pCache->pDispatch->CreateShader(GL_FRAGMENT_SHADER);
if (!uiShader)
{
crWarning("CreateShader failed");
return VERR_NOT_SUPPORTED;
}
pCache->pDispatch->ShaderSource(uiShader, 1, &pStrFsShader, NULL);
pCache->pDispatch->CompileShader(uiShader);
GLint compiled = 0;
pCache->pDispatch->GetShaderiv(uiShader, GL_COMPILE_STATUS, &compiled);
#ifndef DEBUG_misha
if(!compiled)
#endif
{
if (!pBuf)
pBuf = (GLchar *)RTMemAlloc(16300);
pCache->pDispatch->GetShaderInfoLog(uiShader, 16300, NULL, pBuf);
#ifdef DEBUG_misha
if (compiled)
crDebug("compile success:\n-------------------\n%s\n--------\n", pBuf);
else
#endif
{
crWarning("compile FAILURE:\n-------------------\n%s\n--------\n", pBuf);
rc = VERR_NOT_SUPPORTED;
goto end;
}
}
Assert(compiled);
uiProgram = pCache->pDispatch->CreateProgram();
if (!uiProgram)
{
rc = VERR_NOT_SUPPORTED;
goto end;
}
pCache->pDispatch->AttachShader(uiProgram, uiShader);
pCache->pDispatch->LinkProgram(uiProgram);
GLint linked;
pCache->pDispatch->GetProgramiv(uiProgram, GL_LINK_STATUS, &linked);
#ifndef DEBUG_misha
if(!linked)
#endif
{
if (!pBuf)
pBuf = (GLchar *)RTMemAlloc(16300);
pCache->pDispatch->GetProgramInfoLog(uiProgram, 16300, NULL, pBuf);
#ifdef DEBUG_misha
if (linked)
crDebug("link success:\n-------------------\n%s\n--------\n", pBuf);
else
#endif
{
crWarning("link FAILURE:\n-------------------\n%s\n--------\n", pBuf);
rc = VERR_NOT_SUPPORTED;
goto end;
}
}
Assert(linked);
iUniform = pCache->pDispatch->GetUniformLocation(uiProgram, "sampler0");
if (iUniform == -1)
{
crWarning("GetUniformLocation failed for sampler0");
}
else
{
pCache->pDispatch->Uniform1i(iUniform, 0);
}
*puiProgram = uiProgram;
/* avoid end finalizer from cleaning it */
uiProgram = 0;
end:
if (uiShader)
pCache->pDispatch->DeleteShader(uiShader);
if (uiProgram)
pCache->pDispatch->DeleteProgram(uiProgram);
if (pBuf)
RTMemFree(pBuf);
return rc;
}
DECLINLINE(GLuint) crGlslProgGetNoAlpha(const CR_GLSL_CACHE *pCache, GLenum enmTexTarget)
{
switch (enmTexTarget)
{
case GL_TEXTURE_2D:
return pCache->uNoAlpha2DProg;
case GL_TEXTURE_RECTANGLE_ARB:
return pCache->uNoAlpha2DRectProg;
default:
crWarning("invalid tex enmTexTarget %#x", enmTexTarget);
return 0;
}
}
DECLINLINE(GLuint*) crGlslProgGetNoAlphaPtr(CR_GLSL_CACHE *pCache, GLenum enmTexTarget)
{
switch (enmTexTarget)
{
case GL_TEXTURE_2D:
return &pCache->uNoAlpha2DProg;
case GL_TEXTURE_RECTANGLE_ARB:
return &pCache->uNoAlpha2DRectProg;
default:
crWarning("invalid tex enmTexTarget %#x", enmTexTarget);
return NULL;
}
}
VBOXBLITTERDECL(int) CrGlslProgGenNoAlpha(CR_GLSL_CACHE *pCache, GLenum enmTexTarget)
{
GLuint*puiProgram = crGlslProgGetNoAlphaPtr(pCache, enmTexTarget);
if (!puiProgram)
return VERR_INVALID_PARAMETER;
if (*puiProgram)
return VINF_SUCCESS;
return crGlslProgGenNoAlpha(pCache, enmTexTarget, puiProgram);
}
VBOXBLITTERDECL(int) CrGlslProgGenAllNoAlpha(CR_GLSL_CACHE *pCache)
{
int rc = CrGlslProgGenNoAlpha(pCache, GL_TEXTURE_2D);
if (!RT_SUCCESS(rc))
{
crWarning("CrGlslProgGenNoAlpha GL_TEXTURE_2D failed rc %d", rc);
return rc;
}
rc = CrGlslProgGenNoAlpha(pCache, GL_TEXTURE_RECTANGLE_ARB);
if (!RT_SUCCESS(rc))
{
crWarning("CrGlslProgGenNoAlpha GL_TEXTURE_RECTANGLE failed rc %d", rc);
return rc;
}
return VINF_SUCCESS;
}
VBOXBLITTERDECL(void) CrGlslProgClear(const CR_GLSL_CACHE *pCache)
{
pCache->pDispatch->UseProgram(0);
}
VBOXBLITTERDECL(int) CrGlslProgUseNoAlpha(const CR_GLSL_CACHE *pCache, GLenum enmTexTarget)
{
GLuint uiProg = crGlslProgGetNoAlpha(pCache, enmTexTarget);
if (!uiProg)
{
crWarning("request to use inexistent program!");
return VERR_INVALID_STATE;
}
Assert(uiProg);
pCache->pDispatch->UseProgram(uiProg);
return VINF_SUCCESS;
}
VBOXBLITTERDECL(int) CrGlslProgUseGenNoAlpha(CR_GLSL_CACHE *pCache, GLenum enmTexTarget)
{
GLuint uiProg = crGlslProgGetNoAlpha(pCache, enmTexTarget);
if (!uiProg)
{
int rc = CrGlslProgGenNoAlpha(pCache, enmTexTarget);
if (!RT_SUCCESS(rc))
{
crWarning("CrGlslProgGenNoAlpha failed, rc %d", rc);
return rc;
}
uiProg = crGlslProgGetNoAlpha(pCache, enmTexTarget);
CRASSERT(uiProg);
}
Assert(uiProg);
pCache->pDispatch->UseProgram(uiProg);
return VINF_SUCCESS;
}
VBOXBLITTERDECL(bool) CrGlslNeedsCleanup(const CR_GLSL_CACHE *pCache)
{
return pCache->uNoAlpha2DProg || pCache->uNoAlpha2DRectProg;
}
VBOXBLITTERDECL(void) CrGlslCleanup(CR_GLSL_CACHE *pCache)
{
if (pCache->uNoAlpha2DProg)
{
pCache->pDispatch->DeleteProgram(pCache->uNoAlpha2DProg);
pCache->uNoAlpha2DProg = 0;
}
if (pCache->uNoAlpha2DRectProg)
{
pCache->pDispatch->DeleteProgram(pCache->uNoAlpha2DRectProg);
pCache->uNoAlpha2DRectProg = 0;
}
}
VBOXBLITTERDECL(void) CrGlslTerm(CR_GLSL_CACHE *pCache)
{
CRASSERT(!CrGlslNeedsCleanup(pCache));
CrGlslCleanup(pCache);
/* sanity */
memset(pCache, 0, sizeof (*pCache));
}
/*TdBlt*/
static void crTdBltCheckPBO(PCR_TEXDATA pTex)
{
if (pTex->idPBO)
return;
PCR_BLITTER pBlitter = pTex->pBlitter;
if (!pBlitter->Flags.SupportsPBO)
return;
pBlitter->pDispatch->GenBuffersARB(1, &pTex->idPBO);
if (!pTex->idPBO)
{
crWarning("PBO create failed");
return;
}
pBlitter->pDispatch->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pTex->idPBO);
pBlitter->pDispatch->BufferDataARB(GL_PIXEL_PACK_BUFFER_ARB,
pTex->Tex.width*pTex->Tex.height*4,
0, GL_STREAM_READ_ARB);
pBlitter->pDispatch->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
}
static uint32_t crTdBltTexCreate(PCR_TEXDATA pTex)
{
PCR_BLITTER pBlitter = pTex->pBlitter;
uint32_t tex = 0;
pBlitter->pDispatch->GenTextures(1, &tex);
if (!tex)
{
crWarning("Tex create failed");
return 0;
}
pBlitter->pDispatch->BindTexture(GL_TEXTURE_2D, tex);
pBlitter->pDispatch->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
pBlitter->pDispatch->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
pBlitter->pDispatch->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
pBlitter->pDispatch->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
pBlitter->pDispatch->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,
pTex->Tex.width,
pTex->Tex.height,
0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
/*Restore gl state*/
pBlitter->pDispatch->BindTexture(GL_TEXTURE_2D, 0);
return tex;
}
int crTdBltCheckInvertTex(PCR_TEXDATA pTex)
{
if (pTex->idInvertTex)
return VINF_SUCCESS;
pTex->idInvertTex = crTdBltTexCreate(pTex);
if (!pTex->idInvertTex)
{
crWarning("Invert Tex create failed");
return VERR_GENERAL_FAILURE;
}
return VINF_SUCCESS;
}
void crTdBltImgFree(PCR_TEXDATA pTex)
{
if (!pTex->Img.pvData)
return;
PCR_BLITTER pBlitter = pTex->pBlitter;
if (pTex->idPBO)
{
Assert(CrBltIsEntered(pBlitter));
pBlitter->pDispatch->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pTex->idPBO);
pBlitter->pDispatch->UnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
pBlitter->pDispatch->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
}
else
RTMemFree(pTex->Img.pvData);
pTex->Img.pvData = NULL;
}
int crTdBltImgAcquire(PCR_TEXDATA pTex, GLenum enmFormat, bool fInverted)
{
int rc = crBltImgInitBaseForTex(&pTex->Tex, &pTex->Img, enmFormat);
if (!RT_SUCCESS(rc))
{
crWarning("crBltImgInitBaseForTex failed rc %d", rc);
return rc;
}
PCR_BLITTER pBlitter = pTex->pBlitter;
void *pvData = NULL;
pBlitter->pDispatch->BindTexture(pTex->Tex.target, fInverted ? pTex->idInvertTex : pTex->Tex.hwid);
pBlitter->pDispatch->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pTex->idPBO);
if (!pTex->idPBO)
{
pvData = RTMemAlloc(4*pTex->Tex.width*pTex->Tex.height);
if (!pvData)
{
crWarning("Out of memory in crTdBltImgAcquire");
return VERR_NO_MEMORY;
}
}
/*read the texture, note pixels are NULL for PBO case as it's offset in the buffer*/
pBlitter->pDispatch->GetTexImage(GL_TEXTURE_2D, 0, enmFormat, GL_UNSIGNED_BYTE, pvData);
/*restore gl state*/
pBlitter->pDispatch->BindTexture(pTex->Tex.target, 0);
if (pTex->idPBO)
{
pvData = pBlitter->pDispatch->MapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);
if (!pvData)
{
crWarning("Failed to MapBuffer in CrHlpGetTexImage");
return VERR_GENERAL_FAILURE;
}
pBlitter->pDispatch->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
}
CRASSERT(pvData);
pTex->Img.pvData = pvData;
pTex->Flags.DataInverted = fInverted;
return VINF_SUCCESS;
}
/* release the texture data, the data remains cached in the CR_TEXDATA object until it is discarded with CrTdBltDataDiscard or CrTdBltDataCleanup */
VBOXBLITTERDECL(int) CrTdBltDataRelease(PCR_TEXDATA pTex)
{
if (!pTex->Flags.Entered)
{
WARN(("tex not entered"));
return VERR_INVALID_STATE;
}
Assert(pTex->Img.pvData);
return VINF_SUCCESS;
}
/* discard the texture data cached with previous CrTdBltDataAcquire.
* Must be called wit data released (CrTdBltDataRelease) */
VBOXBLITTERDECL(int) CrTdBltDataDiscard(PCR_TEXDATA pTex)
{
if (!pTex->Flags.Entered)
{
WARN(("tex not entered"));
return VERR_INVALID_STATE;
}
crTdBltImgFree(pTex);
return VINF_SUCCESS;
}
VBOXBLITTERDECL(int) CrTdBltDataDiscardNe(PCR_TEXDATA pTex)
{
if (!pTex->Img.pvData)
return VINF_SUCCESS;
bool fEntered = false;
if (pTex->idPBO)
{
int rc = CrTdBltEnter(pTex);
if (!RT_SUCCESS(rc))
{
WARN(("err"));
return rc;
}
fEntered = true;
}
crTdBltImgFree(pTex);
if (fEntered)
CrTdBltLeave(pTex);
return VINF_SUCCESS;
}
static void crTdBltDataCleanup(PCR_TEXDATA pTex)
{
crTdBltImgFree(pTex);
PCR_BLITTER pBlitter = pTex->pBlitter;
if (pTex->idPBO)
{
Assert(CrBltIsEntered(pBlitter));
pBlitter->pDispatch->DeleteBuffersARB(1, &pTex->idPBO);
pTex->idPBO = 0;
}
if (pTex->idInvertTex)
{
Assert(CrBltIsEntered(pBlitter));
pBlitter->pDispatch->DeleteTextures(1, &pTex->idInvertTex);
pTex->idInvertTex = 0;
}
}
/* does same as CrTdBltDataDiscard, and in addition cleans up */
VBOXBLITTERDECL(int) CrTdBltDataCleanup(PCR_TEXDATA pTex)
{
if (!pTex->Flags.Entered)
{
WARN(("tex not entered"));
return VERR_INVALID_STATE;
}
crTdBltDataCleanup(pTex);
return VINF_SUCCESS;
}
VBOXBLITTERDECL(int) CrTdBltDataCleanupNe(PCR_TEXDATA pTex)
{
bool fEntered = false;
if (pTex->idPBO || pTex->idInvertTex)
{
int rc = CrTdBltEnter(pTex);
if (!RT_SUCCESS(rc))
{
WARN(("err"));
return rc;
}
fEntered = true;
}
crTdBltDataCleanup(pTex);
if (fEntered)
CrTdBltLeave(pTex);
return VINF_SUCCESS;
}
/* acquire the texture data, returns the cached data in case it is cached.
* the data remains cached in the CR_TEXDATA object until it is discarded with CrTdBltDataDiscard or CrTdBltDataCleanup.
* */
VBOXBLITTERDECL(int) CrTdBltDataAcquire(PCR_TEXDATA pTex, GLenum enmFormat, bool fInverted, const CR_BLITTER_IMG**ppImg)
{
if (!pTex->Flags.Entered)
{
WARN(("tex not entered"));
return VERR_INVALID_STATE;
}
if (pTex->Img.pvData && pTex->Img.enmFormat == enmFormat && !pTex->Flags.DataInverted == !fInverted)
{
*ppImg = &pTex->Img;
return VINF_SUCCESS;
}
crTdBltImgFree(pTex);
crTdBltCheckPBO(pTex);
int rc;
if (fInverted)
{
rc = crTdBltCheckInvertTex(pTex);
if (!RT_SUCCESS(rc))
{
WARN(("crTdBltCheckInvertTex failed rc %d", rc));
return rc;
}
RTRECT SrcRect, DstRect;
VBOXVR_TEXTURE InvertTex;
InvertTex = pTex->Tex;
InvertTex.hwid = pTex->idInvertTex;
SrcRect.xLeft = 0;
SrcRect.yTop = InvertTex.height;
SrcRect.xRight = InvertTex.width;
SrcRect.yBottom = 0;
DstRect.xLeft = 0;
DstRect.yTop = 0;
DstRect.xRight = InvertTex.width;
DstRect.yBottom = InvertTex.height;
CrBltBlitTexTex(pTex->pBlitter, &pTex->Tex, &SrcRect, &InvertTex, &DstRect, 1, 0);
}
rc = crTdBltImgAcquire(pTex, enmFormat, fInverted);
if (!RT_SUCCESS(rc))
{
WARN(("crTdBltImgAcquire failed rc %d", rc));
return rc;
}
*ppImg = &pTex->Img;
return VINF_SUCCESS;
}