зеркало из https://github.com/mozilla/gecko-dev.git
Bug 985545 - Add a helper method to convert SourceSurfaces to a given format. r=Bas
This commit is contained in:
Родитель
03b7d084c7
Коммит
1801770e59
|
@ -7,6 +7,8 @@
|
|||
#include "gfxContext.h"
|
||||
#include "gfxPlatform.h"
|
||||
#include "gfxDrawable.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsRegion.h"
|
||||
#include "yuv_convert.h"
|
||||
#include "ycbcr_to_rgb565.h"
|
||||
|
@ -848,6 +850,76 @@ gfxUtils::ConvertYCbCrToRGB(const PlanarYCbCrData& aData,
|
|||
}
|
||||
}
|
||||
|
||||
/* static */ TemporaryRef<DataSourceSurface>
|
||||
gfxUtils::CopySurfaceToDataSourceSurfaceWithFormat(SourceSurface* aSurface,
|
||||
SurfaceFormat aFormat)
|
||||
{
|
||||
MOZ_ASSERT(aFormat != aSurface->GetFormat(),
|
||||
"Unnecessary - and very expersive - surface format conversion");
|
||||
|
||||
Rect bounds(0, 0, aSurface->GetSize().width, aSurface->GetSize().height);
|
||||
|
||||
if (aSurface->GetType() != SurfaceType::DATA) {
|
||||
// If the surface is NOT of type DATA then its data is not mapped into main
|
||||
// memory. Format conversion is probably faster on the GPU, and by doing it
|
||||
// there we can avoid any expensive uploads/readbacks except for (possibly)
|
||||
// a single readback due to the unavoidable GetDataSurface() call. Using
|
||||
// CreateOffscreenContentDrawTarget ensures the conversion happens on the
|
||||
// GPU.
|
||||
RefPtr<DrawTarget> dt = gfxPlatform::GetPlatform()->
|
||||
CreateOffscreenContentDrawTarget(aSurface->GetSize(), aFormat);
|
||||
// Using DrawSurface() here rather than CopySurface() because CopySurface
|
||||
// is optimized for memcpy and therefore isn't good for format conversion.
|
||||
// Using OP_OVER since in our case it's equivalent to OP_SOURCE and
|
||||
// generally more optimized.
|
||||
dt->DrawSurface(aSurface, bounds, bounds, DrawSurfaceOptions(),
|
||||
DrawOptions(1.0f, CompositionOp::OP_OVER));
|
||||
RefPtr<SourceSurface> surface = dt->Snapshot();
|
||||
return surface->GetDataSurface();
|
||||
}
|
||||
|
||||
// If the surface IS of type DATA then it may or may not be in main memory
|
||||
// depending on whether or not it has been mapped yet. We have no way of
|
||||
// knowing, so we can't be sure if it's best to create a data wrapping
|
||||
// DrawTarget for the conversion or an offscreen content DrawTarget. We could
|
||||
// guess it's not mapped and create an offscreen content DrawTarget, but if
|
||||
// it is then we'll end up uploading the surface data, and most likely the
|
||||
// caller is going to be accessing the resulting surface data, resulting in a
|
||||
// readback (both very expensive operations). Alternatively we could guess
|
||||
// the data is mapped and create a data wrapping DrawTarget and, if the
|
||||
// surface is not in main memory, then we will incure a readback. The latter
|
||||
// of these two "wrong choices" is the least costly (a readback, vs an
|
||||
// upload and a readback), and more than likely the DATA surface that we've
|
||||
// been passed actually IS in main memory anyway. For these reasons it's most
|
||||
// likely best to create a data wrapping DrawTarget here to do the format
|
||||
// conversion.
|
||||
RefPtr<DataSourceSurface> dataSurface =
|
||||
Factory::CreateDataSourceSurface(aSurface->GetSize(), aFormat);
|
||||
DataSourceSurface::MappedSurface map;
|
||||
if (!dataSurface ||
|
||||
!dataSurface->Map(DataSourceSurface::MapType::READ_WRITE, &map)) {
|
||||
return nullptr;
|
||||
}
|
||||
RefPtr<DrawTarget> dt =
|
||||
Factory::CreateDrawTargetForData(BackendType::CAIRO,
|
||||
map.mData,
|
||||
dataSurface->GetSize(),
|
||||
map.mStride,
|
||||
aFormat);
|
||||
if (!dt) {
|
||||
dataSurface->Unmap();
|
||||
return nullptr;
|
||||
}
|
||||
// Using DrawSurface() here rather than CopySurface() because CopySurface
|
||||
// is optimized for memcpy and therefore isn't good for format conversion.
|
||||
// Using OP_OVER since in our case it's equivalent to OP_SOURCE and
|
||||
// generally more optimized.
|
||||
dt->DrawSurface(aSurface, bounds, bounds, DrawSurfaceOptions(),
|
||||
DrawOptions(1.0f, CompositionOp::OP_OVER));
|
||||
dataSurface->Unmap();
|
||||
return dataSurface.forget();
|
||||
}
|
||||
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
/* static */ void
|
||||
gfxUtils::WriteAsPNG(DrawTarget* aDT, const char* aFile)
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include "gfxTypes.h"
|
||||
#include "GraphicsFilter.h"
|
||||
#include "imgIContainer.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
class gfxDrawable;
|
||||
class nsIntRegion;
|
||||
|
@ -22,8 +24,12 @@ class PlanarYCbCrData;
|
|||
|
||||
class gfxUtils {
|
||||
public:
|
||||
typedef mozilla::gfx::DataSourceSurface DataSourceSurface;
|
||||
typedef mozilla::gfx::IntPoint IntPoint;
|
||||
typedef mozilla::gfx::Matrix Matrix;
|
||||
typedef mozilla::gfx::SourceSurface SourceSurface;
|
||||
typedef mozilla::gfx::SurfaceFormat SurfaceFormat;
|
||||
|
||||
/*
|
||||
* Premultiply or Unpremultiply aSourceSurface, writing the result
|
||||
* to aDestSurface or back into aSourceSurface if aDestSurface is null.
|
||||
|
@ -155,6 +161,51 @@ public:
|
|||
unsigned char* aDestBuffer,
|
||||
int32_t aStride);
|
||||
|
||||
/**
|
||||
* Creates a copy of aSurface, but having the SurfaceFormat aFormat.
|
||||
*
|
||||
* This function always creates a new surface. Do not call it if aSurface's
|
||||
* format is the same as aFormat. Such a non-conversion would just be an
|
||||
* unnecessary and wasteful copy (this function asserts to prevent that).
|
||||
*
|
||||
* This function is intended to be called by code that needs to access the
|
||||
* pixel data of the surface, but doesn't want to have lots of branches
|
||||
* to handle different pixel data formats (code which would become out of
|
||||
* date if and when new formats are added). Callers can use this function
|
||||
* to copy the surface to a specified format so that they only have to
|
||||
* handle pixel data in that one format.
|
||||
*
|
||||
* WARNING: There are format conversions that will not be supported by this
|
||||
* function. It very much depends on what the Moz2D backends support. If
|
||||
* the temporary B8G8R8A8 DrawTarget that this function creates has a
|
||||
* backend that supports DrawSurface() calls passing a surface with
|
||||
* aSurface's format it will work. Otherwise it will not.
|
||||
*
|
||||
* *** IMPORTANT PERF NOTE ***
|
||||
*
|
||||
* This function exists partly because format conversion is fraught with
|
||||
* non-obvious performance hazards, so we don't want Moz2D consumers to be
|
||||
* doing their own format conversion. Do not try to do so, or at least read
|
||||
* the comments in this functions implemtation. That said, the copy that
|
||||
* this function carries out has a cost and, although this function tries
|
||||
* to avoid perf hazards such as expensive uploads to/readbacks from the
|
||||
* GPU, it can't guarantee that it always successfully does so. Perf
|
||||
* critical code that can directly handle the common formats that it
|
||||
* encounters in a way that is cheaper than a copy-with-format-conversion
|
||||
* should consider doing so, and only use this function as a fallback to
|
||||
* handle other formats.
|
||||
*
|
||||
* XXXjwatt it would be nice if SourceSurface::GetDataSurface took a
|
||||
* SurfaceFormat argument (with a default argument meaning "use the
|
||||
* existing surface's format") and returned a DataSourceSurface in that
|
||||
* format. (There would then be an issue of callers maybe failing to
|
||||
* realize format conversion may involve expensive copying/uploading/
|
||||
* readback.)
|
||||
*/
|
||||
static mozilla::TemporaryRef<DataSourceSurface>
|
||||
CopySurfaceToDataSourceSurfaceWithFormat(SourceSurface* aSurface,
|
||||
SurfaceFormat aFormat);
|
||||
|
||||
static const uint8_t sUnpremultiplyTable[256*256];
|
||||
static const uint8_t sPremultiplyTable[256*256];
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
|
|
Загрузка…
Ссылка в новой задаче