Skip to content

Commit

Permalink
Avoid excessive copying in BitmapData.setPixel and elsewhere
Browse files Browse the repository at this point in the history
Before this change every setPixel call caused the whole bitmap to be
copied. By using smartrefs of BitmapContainers, the actual pixel data
is not copied. One BitmapContainer is shared between all Bitmaps using
the same BitmapData.

The reference counting is moved into a new RefCountable base class.
  • Loading branch information
aajanki committed Mar 3, 2013
1 parent 4581b5f commit c425e99
Show file tree
Hide file tree
Showing 14 changed files with 335 additions and 250 deletions.
12 changes: 6 additions & 6 deletions src/asobject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -456,8 +456,6 @@ void ASObject::setDeclaredMethodByQName(uint32_t nameId, const nsNameAndKind& ns

bool ASObject::deleteVariableByMultiname(const multiname& name)
{
assert_and_throw(ref_count>0);

variable* obj=Variables.findObjVar(name,NO_CREATE_TRAIT,DYNAMIC_TRAIT|DECLARED_TRAIT);

if(obj==NULL)
Expand Down Expand Up @@ -1028,7 +1026,9 @@ _NR<ASObject> ASObject::executeASMethod(const tiny_string& methodName,
void ASObject::check() const
{
//Put here a bunch of safety check on the object
assert(ref_count>0);
#ifndef NDEBUG
assert(getRefCount()>0);
#endif
Variables.check();
}

Expand Down Expand Up @@ -1113,7 +1113,7 @@ void variables_map::destroyContents()
}

ASObject::ASObject(MemoryAccount* m):Variables(m),classdef(NULL),
ref_count(1),type(T_OBJECT),traitsInitialized(false),implEnable(true)
type(T_OBJECT),traitsInitialized(false),implEnable(true)
{
#ifndef NDEBUG
//Stuff only used in debugging
Expand All @@ -1122,7 +1122,7 @@ ASObject::ASObject(MemoryAccount* m):Variables(m),classdef(NULL),
}

ASObject::ASObject(Class_base* c):Variables((c)?c->memoryAccount:NULL),classdef(NULL),
ref_count(1),type(T_OBJECT),traitsInitialized(false),implEnable(true)
type(T_OBJECT),traitsInitialized(false),implEnable(true)
{
setClass(c);
#ifndef NDEBUG
Expand All @@ -1132,7 +1132,7 @@ ASObject::ASObject(Class_base* c):Variables((c)?c->memoryAccount:NULL),classdef(
}

ASObject::ASObject(const ASObject& o):Variables((o.classdef)?o.classdef->memoryAccount:NULL),classdef(NULL),
ref_count(1),type(o.type),traitsInitialized(false),implEnable(true)
type(o.type),traitsInitialized(false),implEnable(true)
{
if(o.classdef)
setClass(o.classdef);
Expand Down
27 changes: 1 addition & 26 deletions src/asobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ enum METHOD_TYPE { NORMAL_METHOD=0, SETTER_METHOD=1, GETTER_METHOD=2 };
//for toPrimitive
enum TP_HINT { NO_HINT, NUMBER_HINT, STRING_HINT };

class ASObject: public memory_reporter, public boost::intrusive::list_base_hook<>
class ASObject: public memory_reporter, public boost::intrusive::list_base_hook<>, public RefCountable
{
friend class ABCVm;
friend class ABCContext;
Expand All @@ -251,7 +251,6 @@ friend class IFunction; //Needed for clone
private:
variables_map Variables;
Class_base* classdef;
ATOMIC_INT32(ref_count);
const variable* findGettable(const multiname& name) const DLL_LOCAL;
variable* findSettable(const multiname& name, bool* has_getter=NULL) DLL_LOCAL;
protected:
Expand All @@ -271,7 +270,6 @@ friend class IFunction; //Needed for clone
#ifndef NDEBUG
//Stuff only used in debugging
bool initialized:1;
int getRefCount(){ return ref_count; }
#endif
bool implEnable:1;
Class_base* getClass() const { return classdef; }
Expand All @@ -282,29 +280,6 @@ friend class IFunction; //Needed for clone
ASFUNCTION(isPrototypeOf);
ASFUNCTION(propertyIsEnumerable);
void check() const;
void incRef()
{
//std::cout << "incref " << this << std::endl;
ATOMIC_INCREMENT(ref_count);
assert(ref_count>0);
}
void decRef()
{
//std::cout << "decref " << this << std::endl;
assert(ref_count>0);
uint32_t t=ATOMIC_DECREMENT(ref_count);
if(t==0)
{
//Let's make refcount very invalid
ref_count=-1024;
//std::cout << "delete " << this << std::endl;
delete this;
}
}
void fake_decRef()
{
ATOMIC_DECREMENT(ref_count);
}
static void s_incRef(ASObject* o)
{
o->incRef();
Expand Down
13 changes: 9 additions & 4 deletions src/backends/graphics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -343,11 +343,16 @@ cairo_pattern_t* CairoTokenRenderer::FILLSTYLEToCairo(const FILLSTYLE& style, do
case REPEATING_BITMAP:
case CLIPPED_BITMAP:
{
//bitmap is always present, it may be empty though
_NR<BitmapContainer> bm(style.bitmap);
if(bm.isNull())
return NULL;

//Do an explicit cast, the data will not be modified
cairo_surface_t* surface = cairo_image_surface_create_for_data ((uint8_t*)style.bitmap.getData(),
CAIRO_FORMAT_ARGB32, style.bitmap.getWidth(), style.bitmap.getHeight(),
cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, style.bitmap.getWidth()));
cairo_surface_t* surface = cairo_image_surface_create_for_data ((uint8_t*)bm->getData(),
CAIRO_FORMAT_ARGB32,
bm->getWidth(),
bm->getHeight(),
cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, bm->getWidth()));

pattern = cairo_pattern_create_for_surface(surface);
cairo_surface_destroy(surface);
Expand Down
30 changes: 15 additions & 15 deletions src/parsing/tags.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -753,7 +753,7 @@ ASObject* DefineFont4Tag::instance(Class_base* c) const
return ret;
}

BitmapTag::BitmapTag(RECORDHEADER h,RootMovieClip* root):DictionaryTag(h,root),BitmapContainer(getSys()->tagsMemory)
BitmapTag::BitmapTag(RECORDHEADER h,RootMovieClip* root):DictionaryTag(h,root),bitmap(_MR(new BitmapContainer(getSys()->tagsMemory)))
{
}

Expand Down Expand Up @@ -784,13 +784,13 @@ DefineBitsLosslessTag::DefineBitsLosslessTag(RECORDHEADER h, istream& in, int ve

BitmapContainer::BITMAP_FORMAT format;
if (BitmapFormat == LOSSLESS_BITMAP_RGB15)
format = RGB15;
format = BitmapContainer::RGB15;
else if (version == 1)
format = RGB24;
format = BitmapContainer::RGB24;
else
format = ARGB32;
format = BitmapContainer::ARGB32;

fromRGB(inData, BitmapWidth, BitmapHeight, format);
bitmap->fromRGB(inData, BitmapWidth, BitmapHeight, format);
}
else if (BitmapFormat == LOSSLESS_BITMAP_PALETTE)
{
Expand All @@ -814,7 +814,7 @@ DefineBitsLosslessTag::DefineBitsLosslessTag(RECORDHEADER h, istream& in, int ve

uint8_t *palette = inData;
uint8_t *pixelData = inData + paletteBPP*numColors;
fromPalette(pixelData, BitmapWidth, BitmapHeight, stride, palette, numColors, paletteBPP);
bitmap->fromPalette(pixelData, BitmapWidth, BitmapHeight, stride, palette, numColors, paletteBPP);
delete[] inData;
}
else
Expand All @@ -832,11 +832,11 @@ ASObject* BitmapTag::instance(Class_base* c) const
Class_base* classRet = Class<BitmapData>::getClass();

if(!realClass)
return new (classRet->memoryAccount) BitmapData(classRet, *this);
return new (classRet->memoryAccount) BitmapData(classRet, bitmap);

if(realClass->isSubClass(Class<Bitmap>::getClass()))
{
BitmapData* ret=new (classRet->memoryAccount) BitmapData(classRet, *this);
BitmapData* ret=new (classRet->memoryAccount) BitmapData(classRet, bitmap);
Bitmap* bitmapRet=new (realClass->memoryAccount) Bitmap(realClass,_MR(ret));
return bitmapRet;
}
Expand All @@ -846,7 +846,7 @@ ASObject* BitmapTag::instance(Class_base* c) const
classRet = realClass;
}

return new (classRet->memoryAccount) BitmapData(classRet, *this);
return new (classRet->memoryAccount) BitmapData(classRet, bitmap);
}

DefineTextTag::DefineTextTag(RECORDHEADER h, istream& in, RootMovieClip* root,int v):DictionaryTag(h,root),
Expand Down Expand Up @@ -1664,7 +1664,7 @@ DefineBitsTag::DefineBitsTag(RECORDHEADER h, std::istream& in,RootMovieClip* roo
int dataSize=Header.getLength()-2;
uint8_t *inData=new(nothrow) uint8_t[dataSize];
in.read((char*)inData,dataSize);
fromJPEG(inData,dataSize,JPEGTablesTag::getJPEGTables(),JPEGTablesTag::getJPEGTableSize());
bitmap->fromJPEG(inData,dataSize,JPEGTablesTag::getJPEGTables(),JPEGTablesTag::getJPEGTableSize());
delete[] inData;
}

Expand All @@ -1677,7 +1677,7 @@ DefineBitsJPEG2Tag::DefineBitsJPEG2Tag(RECORDHEADER h, std::istream& in, RootMov
uint8_t* inData=new(nothrow) uint8_t[dataSize];
in.read((char*)inData,dataSize);

fromJPEG(inData,dataSize);
bitmap->fromJPEG(inData,dataSize);
delete[] inData;
}

Expand All @@ -1691,7 +1691,7 @@ DefineBitsJPEG3Tag::DefineBitsJPEG3Tag(RECORDHEADER h, std::istream& in, RootMov
in.read((char*)inData,dataSize);

//TODO: check header. Could also be PNG or GIF
fromJPEG(inData,dataSize);
bitmap->fromJPEG(inData,dataSize);
delete[] inData;

//Read alpha data (if any)
Expand All @@ -1711,10 +1711,10 @@ DefineBitsJPEG3Tag::DefineBitsJPEG3Tag(RECORDHEADER h, std::istream& in, RootMov
try
{
//Set alpha
for(int32_t i=0;i<height;i++)
for(int32_t i=0;i<bitmap->getHeight();i++)
{
for(int32_t j=0;j<width;j++)
data[i*stride + j*4 + 3]=zfstream.get();
for(int32_t j=0;j<bitmap->getWidth();j++)
bitmap->setAlpha(i, j, zfstream.get());
}
}
catch(std::exception& e)
Expand Down
5 changes: 4 additions & 1 deletion src/parsing/tags.h
Original file line number Diff line number Diff line change
Expand Up @@ -523,11 +523,14 @@ class ProtectTag: public ControlTag
void execute(RootMovieClip* root) const{};
};

class BitmapTag: public DictionaryTag, public BitmapContainer
class BitmapTag: public DictionaryTag
{
protected:
_R<BitmapContainer> bitmap;
public:
BitmapTag(RECORDHEADER h,RootMovieClip* root);
ASObject* instance(Class_base* c=NULL) const;
_R<BitmapContainer> getBitmap() const { return bitmap; }
};

class JPEGTablesTag: public Tag
Expand Down
Loading

0 comments on commit c425e99

Please sign in to comment.