Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(850)

Side by Side Diff: src/core/SkPictureFlat.h

Issue 19564007: Start from scratch on a faster SkFlatDictionary. (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: fix memory overwrite and tests Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 1
2 /* 2 /*
3 * Copyright 2011 Google Inc. 3 * Copyright 2011 Google Inc.
4 * 4 *
5 * Use of this source code is governed by a BSD-style license that can be 5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file. 6 * found in the LICENSE file.
7 */ 7 */
8 #ifndef SkPictureFlat_DEFINED 8 #ifndef SkPictureFlat_DEFINED
9 #define SkPictureFlat_DEFINED 9 #define SkPictureFlat_DEFINED
10 10
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after
144 // 144 //
145 // The following templated classes provide an efficient way to store and compare 145 // The following templated classes provide an efficient way to store and compare
146 // objects that have been flattened (i.e. serialized in an ordered binary 146 // objects that have been flattened (i.e. serialized in an ordered binary
147 // format). 147 // format).
148 // 148 //
149 // SkFlatData: is a simple indexable container for the flattened data 149 // SkFlatData: is a simple indexable container for the flattened data
150 // which is agnostic to the type of data is is indexing. It is 150 // which is agnostic to the type of data is is indexing. It is
151 // also responsible for flattening/unflattening objects but 151 // also responsible for flattening/unflattening objects but
152 // details of that operation are hidden in the provided procs 152 // details of that operation are hidden in the provided procs
153 // SkFlatDictionary: is an abstract templated dictionary that maintains a 153 // SkFlatDictionary: is an abstract templated dictionary that maintains a
154 // searchable set of SkFlataData objects of type T. 154 // searchable set of SkFlatData objects of type T.
155 // SkFlatController: is an interface provided to SkFlatDictionary which handles 155 // SkFlatController: is an interface provided to SkFlatDictionary which handles
156 // allocation and unallocation in some cases. It also holds 156 // allocation (and unallocation in some cases). It also holds
157 // ref count recorders and the like. 157 // ref count recorders and the like.
158 // 158 //
159 // NOTE: any class that wishes to be used in conjunction with SkFlatDictionary 159 // NOTE: any class that wishes to be used in conjunction with SkFlatDictionary
160 // must subclass the dictionary and provide the necessary flattening procs. 160 // must subclass the dictionary and provide the necessary flattening procs.
161 // The end of this header contains dictionary subclasses for some common classes 161 // The end of this header contains dictionary subclasses for some common classes
162 // like SkBitmap, SkMatrix, SkPaint, and SkRegion. SkFlatController must also 162 // like SkBitmap, SkMatrix, SkPaint, and SkRegion. SkFlatController must also
163 // be implemented, or SkChunkFlatController can be used to use an 163 // be implemented, or SkChunkFlatController can be used to use an
164 // SkChunkAllocator and never do replacements. 164 // SkChunkAllocator and never do replacements.
165 // 165 //
166 // 166 //
167 /////////////////////////////////////////////////////////////////////////////// 167 ///////////////////////////////////////////////////////////////////////////////
168 168
169 class SkFlatData; 169 class SkFlatData;
170 170
171 class SkFlatController : public SkRefCnt { 171 class SkFlatController : public SkRefCnt {
172 public: 172 public:
173 SK_DECLARE_INST_COUNT(SkFlatController) 173 SK_DECLARE_INST_COUNT(SkFlatController)
174 174
175 SkFlatController(); 175 SkFlatController();
176 virtual ~SkFlatController(); 176 virtual ~SkFlatController();
177 /** 177 /**
178 * Provide a new block of memory for the SkFlatDictionary to use. 178 * Provide a new block of memory for the SkFlatDictionary to use.
179 * This memory is owned by the controller and has the same lifetime unless y ou
180 * call unalloc(), in which case it may be freed early.
tomhudson 2013/07/22 16:36:02 Nit: While we're fixing up this comment, the funct
mtklein 2013/07/22 17:43:56 How about a nice, neutral "Return"?
179 */ 181 */
180 virtual void* allocThrow(size_t bytes) = 0; 182 virtual void* allocThrow(size_t bytes) = 0;
181 183
182 /** 184 /**
183 * Unallocate a previously allocated block, returned by allocThrow. 185 * Hint that this block, which was allocated with allocThrow, is no longer n eeded.
184 * Implementation should at least perform an unallocation if passed the last 186 * The implementation may choose to free this memory any time beteween now a nd destruction.
185 * pointer returned by allocThrow. If findAndReplace() is intended to be
186 * used, unalloc should also be able to unallocate the SkFlatData that is
187 * provided.
188 */ 187 */
189 virtual void unalloc(void* ptr) = 0; 188 virtual void unalloc(void* ptr) = 0;
190 189
191 /** 190 /**
192 * Used during creation and unflattening of SkFlatData objects. If the 191 * Used during creation and unflattening of SkFlatData objects. If the
193 * objects being flattened contain bitmaps they are stored in this heap 192 * objects being flattened contain bitmaps they are stored in this heap
194 * and the flattenable stores the index to the bitmap on the heap. 193 * and the flattenable stores the index to the bitmap on the heap.
195 * This should be set by the protected setBitmapHeap. 194 * This should be set by the protected setBitmapHeap.
196 */ 195 */
197 SkBitmapHeap* getBitmapHeap() { return fBitmapHeap; } 196 SkBitmapHeap* getBitmapHeap() { return fBitmapHeap; }
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after
393 } 392 }
394 393
395 enum { 394 enum {
396 kInCache_Sentinel = 0, 395 kInCache_Sentinel = 0,
397 kCandidate_Sentinel = ~0U, 396 kCandidate_Sentinel = ~0U,
398 }; 397 };
399 void setSentinel(uint32_t value) { 398 void setSentinel(uint32_t value) {
400 SkASSERT(SkIsAlign4(fFlatSize)); 399 SkASSERT(SkIsAlign4(fFlatSize));
401 this->data32()[fFlatSize >> 2] = value; 400 this->data32()[fFlatSize >> 2] = value;
402 } 401 }
402
403 void init(int index, int32_t size);
404 template <class T> friend class SkFlatDictionary; // For init().
403 }; 405 };
404 406
405 template <class T> 407 template <class T>
406 class SkFlatDictionary { 408 class SkFlatDictionary {
409 static const size_t kWriteBufferGrowthBytes = 1024;
410
407 public: 411 public:
408 SkFlatDictionary(SkFlatController* controller) 412 SkFlatDictionary(SkFlatController* controller)
409 : fController(controller) { 413 : fFlattenProc(NULL)
410 fFlattenProc = NULL; 414 , fUnflattenProc(NULL)
411 fUnflattenProc = NULL; 415 , fController(SkRef(controller))
412 SkASSERT(controller); 416 , fNextIndex(1) // set to 1 since returning a zero from find() indicates fa ilure
413 fController->ref(); 417 , fDataSize(0)
414 // set to 1 since returning a zero from find() indicates failure 418 , fFlatData(this->allocFlatData(fDataSize))
415 fNextIndex = 1; 419 , fWriteBuffer(kWriteBufferGrowthBytes)
420 , fWriteBufferReady(false) {
416 sk_bzero(fHash, sizeof(fHash)); 421 sk_bzero(fHash, sizeof(fHash));
417 // index 0 is always empty since it is used as a signal that find failed 422 // index 0 is always empty since it is used as a signal that find failed
418 fIndexedData.push(NULL); 423 fIndexedData.push(NULL);
419 } 424 }
420 425
421 virtual ~SkFlatDictionary() {
422 fController->unref();
423 }
424
425 int count() const { 426 int count() const {
426 SkASSERT(fIndexedData.count() == fSortedData.count()+1); 427 SkASSERT(fIndexedData.count() == fSortedData.count()+1);
427 return fSortedData.count(); 428 return fSortedData.count();
428 } 429 }
429 430
430 const SkFlatData* operator[](int index) const { 431 const SkFlatData* operator[](int index) const {
431 SkASSERT(index >= 0 && index < fSortedData.count()); 432 SkASSERT(index >= 0 && index < fSortedData.count());
432 return fSortedData[index]; 433 return fSortedData[index];
433 } 434 }
434 435
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
525 SkASSERT(fIndexedData.count() == fSortedData.count()+1); 526 SkASSERT(fIndexedData.count() == fSortedData.count()+1);
526 const SkFlatData* element = fIndexedData[index]; 527 const SkFlatData* element = fIndexedData[index];
527 SkASSERT(index == element->index()); 528 SkASSERT(index == element->index());
528 529
529 T* dst = new T; 530 T* dst = new T;
530 this->unflatten(dst, element); 531 this->unflatten(dst, element);
531 return dst; 532 return dst;
532 } 533 }
533 534
534 const SkFlatData* findAndReturnFlat(const T& element) { 535 const SkFlatData* findAndReturnFlat(const T& element) {
535 SkFlatData* flat = SkFlatData::Create(fController, &element, fNextIndex, fFlattenProc); 536 const SkFlatData& temp = this->getTemporary(element, fNextIndex);
536 537
537 int hashIndex = ChecksumToHashIndex(flat->checksum()); 538 // See if we have it in the hash?
539 const int hashIndex = ChecksumToHashIndex(temp.checksum());
538 const SkFlatData* candidate = fHash[hashIndex]; 540 const SkFlatData* candidate = fHash[hashIndex];
539 if (candidate && !SkFlatData::Compare(*flat, *candidate)) { 541 if (candidate != NULL && SkFlatData::Compare(temp, *candidate) == 0) ret urn candidate;
540 fController->unalloc(flat);
541 return candidate;
542 }
543 542
544 int index = SkTSearch<const SkFlatData, 543 // See if we have it at all?
545 SkFlatData::Less>((const SkFlatData**) fSortedData .begin(), 544 const int index = SkTSearch<const SkFlatData, SkFlatData::Less>(fSortedD ata.begin(),
546 fSortedData.count(), flat, sizeo f(flat)); 545 fSortedD ata.count(),
546 &temp,
547 sizeof(& temp));
547 if (index >= 0) { 548 if (index >= 0) {
548 fController->unalloc(flat); 549 // Found. Update hash before we return.
549 fHash[hashIndex] = fSortedData[index]; 550 fHash[hashIndex] = fSortedData[index];
550 return fSortedData[index]; 551 return fSortedData[index];
551 } 552 }
552 553
553 index = ~index; 554 // We don't have it. Add it.
554 *fSortedData.insert(index) = flat; 555 SkFlatData* durable = this->getDurable();
555 *fIndexedData.insert(flat->index()) = flat; 556 *fSortedData.insert(~index) = durable; // SkTSearch returned bit-not of where to insert.
557 *fIndexedData.insert(durable->index()) = durable;
558 fHash[hashIndex] = durable;
559
560 SkASSERT(durable->index() == fNextIndex);
556 SkASSERT(fSortedData.count() == fNextIndex); 561 SkASSERT(fSortedData.count() == fNextIndex);
562 SkASSERT(fIndexedData.count() == fNextIndex+1);
557 fNextIndex++; 563 fNextIndex++;
558 flat->setSentinelInCache(); 564
559 fHash[hashIndex] = flat; 565 return durable;
560 SkASSERT(fIndexedData.count() == fSortedData.count()+1);
561 return flat;
562 } 566 }
563 567
564 protected: 568 protected:
565 void (*fFlattenProc)(SkOrderedWriteBuffer&, const void*); 569 void (*fFlattenProc)(SkOrderedWriteBuffer&, const void*);
566 void (*fUnflattenProc)(SkOrderedReadBuffer&, void*); 570 void (*fUnflattenProc)(SkOrderedReadBuffer&, void*);
567 571
568 private: 572 private:
573 // Layout: [ SkFlatData header, 20 bytes ] [ data ... ] [ sentinel, 4 bytes]
tomhudson 2013/07/22 16:36:02 Nit: Do we need to worry (or assert?) about the al
mtklein 2013/07/22 17:43:56 Oh, good call. Using SkWriter32 guarantees that d
574 uint8_t* allocFlatData(size_t dataSize) {
575 return (uint8_t*) fController->allocThrow(sizeof(SkFlatData) + dataSize + sizeof(uint32_t));
576 }
577
578 // Returns a pointer to where we should start writing flattened data (just p ast the header).
579 static uint8_t* dataStart(uint8_t* flatData) {
580 return flatData + sizeof(SkFlatData);
581 }
582
583 // We have to delay fWriteBuffer's initialization until its first use; fCont roller might not
584 // be fully set up by the time we get it in the constructor.
585 void lazyWriteBufferInit() {
586 if (fWriteBufferReady) return;
587 // Without a bitmap heap, we'll flatten bitmaps into paints. That's nev er what you want.
588 SkASSERT(fController->getBitmapHeap() != NULL);
589 fWriteBuffer.setBitmapHeap(fController->getBitmapHeap());
590 fWriteBuffer.setTypefaceRecorder(fController->getTypefaceSet());
591 fWriteBuffer.setNamedFactoryRecorder(fController->getNamedFactorySet());
592 fWriteBuffer.setFlags(fController->getWriteBufferFlags());
593 fWriteBufferReady = true;
594 }
595
596 // This reference is valid only until the next call to getTemporary() or get Durable().
597 const SkFlatData& getTemporary(const T& element, int index) {
598 lazyWriteBufferInit();
tomhudson 2013/07/22 16:36:02 this->lazyWriteBufferInit();
mtklein 2013/07/22 17:43:56 Done.
599
600 // If all the flattened bytes fit into fFlatData, we can skip the call t o writeToMemory.
601 fWriteBuffer.reset(this->dataStart(fFlatData), fDataSize);
602 fFlattenProc(fWriteBuffer, &element);
603 const size_t size = fWriteBuffer.size();
604
605 if (!fWriteBuffer.wroteOnlyToStorage()) {
606 // It didn't all fit. Copy into a bigger replacement fFlatData.
607 SkASSERT(size > fDataSize);
608 uint8_t* bigger = this->allocFlatData(size);
609 fWriteBuffer.writeToMemory(this->dataStart(bigger));
610 fController->unalloc(fFlatData);
611 fDataSize = size;
612 fFlatData = bigger;
613 }
614
615 // The data is in fFlatData now, but we need to stamp its header and tra iling sentinel.
616 SkFlatData* temp = (SkFlatData*)fFlatData;
617 temp->init(index, size);
618 return *temp;
619 }
620
621 // This result is owned by fController and lives as long as it does (unless unalloc'd).
622 SkFlatData* getDurable() {
623 SkFlatData* durable = (SkFlatData*)fFlatData;
624 durable->setSentinelInCache();
625 // The next flat data we see has a good chance of being at least this bi g.
626 fFlatData = this->allocFlatData(fDataSize);
627 return durable;
628 }
629
569 void unflatten(T* dst, const SkFlatData* element) const { 630 void unflatten(T* dst, const SkFlatData* element) const {
570 element->unflatten(dst, fUnflattenProc, 631 element->unflatten(dst, fUnflattenProc,
571 fController->getBitmapHeap(), 632 fController->getBitmapHeap(),
572 fController->getTypefacePlayback()); 633 fController->getTypefacePlayback());
573 } 634 }
574 635
575 void unflattenIntoArray(T* array) const { 636 void unflattenIntoArray(T* array) const {
576 const int count = fSortedData.count(); 637 const int count = fSortedData.count();
577 SkASSERT(fIndexedData.count() == fSortedData.count()+1); 638 SkASSERT(fIndexedData.count() == fSortedData.count()+1);
578 const SkFlatData* const* iter = fSortedData.begin(); 639 const SkFlatData* const* iter = fSortedData.begin();
579 for (int i = 0; i < count; ++i) { 640 for (int i = 0; i < count; ++i) {
580 const SkFlatData* element = iter[i]; 641 const SkFlatData* element = iter[i];
581 int index = element->index() - 1; 642 int index = element->index() - 1;
582 SkASSERT((unsigned)index < (unsigned)count); 643 SkASSERT((unsigned)index < (unsigned)count);
583 unflatten(&array[index], element); 644 unflatten(&array[index], element);
584 } 645 }
585 } 646 }
586 647
587 SkFlatController * const fController; 648 SkAutoTUnref<SkFlatController> fController;
588 int fNextIndex; 649 size_t fDataSize;
650 uint8_t* fFlatData; // length == sizeof(SkFlatData) + fDataSize + sizeof(ui nt32_t)
651 SkOrderedWriteBuffer fWriteBuffer;
652 bool fWriteBufferReady;
589 653
590 // SkFlatDictionary has two copies of the data one indexed by the 654 // SkFlatDictionary has two copies of the data one indexed by the
591 // SkFlatData's index and the other sorted. The sorted data is used 655 // SkFlatData's index and the other sorted. The sorted data is used
592 // for finding and uniquification while the indexed copy is used 656 // for finding and uniquification while the indexed copy is used
593 // for standard array-style lookups based on the SkFlatData's index 657 // for standard array-style lookups based on the SkFlatData's index
594 // (as in 'unflatten'). 658 // (as in 'unflatten').
659 int fNextIndex;
595 SkTDArray<const SkFlatData*> fIndexedData; 660 SkTDArray<const SkFlatData*> fIndexedData;
596 // fSortedData is sorted by checksum/size/data. 661 // fSortedData is sorted by checksum/size/data.
597 SkTDArray<const SkFlatData*> fSortedData; 662 SkTDArray<const SkFlatData*> fSortedData;
598 663
599 enum { 664 enum {
600 // Determined by trying diff values on picture-recording benchmarks 665 // Determined by trying diff values on picture-recording benchmarks
601 // (e.g. PictureRecordBench.cpp), choosing the smallest value that 666 // (e.g. PictureRecordBench.cpp), choosing the smallest value that
602 // showed a big improvement. Even better would be to benchmark diff 667 // showed a big improvement. Even better would be to benchmark diff
603 // values on recording representative web-pages or other "real" content. 668 // values on recording representative web-pages or other "real" content.
604 HASH_BITS = 7, 669 HASH_BITS = 7,
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
638 703
639 class SkChunkFlatController : public SkFlatController { 704 class SkChunkFlatController : public SkFlatController {
640 public: 705 public:
641 SkChunkFlatController(size_t minSize) 706 SkChunkFlatController(size_t minSize)
642 : fHeap(minSize) 707 : fHeap(minSize)
643 , fTypefaceSet(SkNEW(SkRefCntSet)) { 708 , fTypefaceSet(SkNEW(SkRefCntSet)) {
644 this->setTypefaceSet(fTypefaceSet); 709 this->setTypefaceSet(fTypefaceSet);
645 this->setTypefacePlayback(&fTypefacePlayback); 710 this->setTypefacePlayback(&fTypefacePlayback);
646 } 711 }
647 712
648 ~SkChunkFlatController() {
649 fTypefaceSet->unref();
650 }
651
652 virtual void* allocThrow(size_t bytes) SK_OVERRIDE { 713 virtual void* allocThrow(size_t bytes) SK_OVERRIDE {
653 return fHeap.allocThrow(bytes); 714 fLastAllocated = fHeap.allocThrow(bytes);
715 return fLastAllocated;
654 } 716 }
655 717
656 virtual void unalloc(void* ptr) SK_OVERRIDE { 718 virtual void unalloc(void* ptr) SK_OVERRIDE {
657 (void) fHeap.unalloc(ptr); 719 // fHeap can only free a pointer if it was the last one allocated. Othe rwise, we'll just
720 // have to wait until fHeap is destroyed.
721 if (ptr == fLastAllocated) (void)fHeap.unalloc(ptr);
658 } 722 }
659 723
660 void setupPlaybacks() const { 724 void setupPlaybacks() const {
661 fTypefacePlayback.reset(fTypefaceSet); 725 fTypefacePlayback.reset(fTypefaceSet.get());
662 } 726 }
663 727
664 void setBitmapStorage(SkBitmapHeap* heap) { 728 void setBitmapStorage(SkBitmapHeap* heap) {
665 this->setBitmapHeap(heap); 729 this->setBitmapHeap(heap);
666 } 730 }
667 731
668 private: 732 private:
669 SkChunkAlloc fHeap; 733 SkChunkAlloc fHeap;
670 SkRefCntSet* fTypefaceSet; 734 SkAutoTUnref<SkRefCntSet> fTypefaceSet;
735 void* fLastAllocated;
671 mutable SkTypefacePlayback fTypefacePlayback; 736 mutable SkTypefacePlayback fTypefacePlayback;
672 }; 737 };
673 738
674 class SkBitmapDictionary : public SkFlatDictionary<SkBitmap> {
675 public:
676 SkBitmapDictionary(SkFlatController* controller)
677 : SkFlatDictionary<SkBitmap>(controller) {
678 fFlattenProc = &SkFlattenObjectProc<SkBitmap>;
679 fUnflattenProc = &SkUnflattenObjectProc<SkBitmap>;
680 }
681 };
682
683 class SkMatrixDictionary : public SkFlatDictionary<SkMatrix> { 739 class SkMatrixDictionary : public SkFlatDictionary<SkMatrix> {
684 public: 740 public:
685 SkMatrixDictionary(SkFlatController* controller) 741 SkMatrixDictionary(SkFlatController* controller)
686 : SkFlatDictionary<SkMatrix>(controller) { 742 : SkFlatDictionary<SkMatrix>(controller) {
687 fFlattenProc = &flattenMatrix; 743 fFlattenProc = &flattenMatrix;
688 fUnflattenProc = &unflattenMatrix; 744 fUnflattenProc = &unflattenMatrix;
689 } 745 }
690 746
691 static void flattenMatrix(SkOrderedWriteBuffer& buffer, const void* obj) { 747 static void flattenMatrix(SkOrderedWriteBuffer& buffer, const void* obj) {
692 buffer.getWriter32()->writeMatrix(*(SkMatrix*)obj); 748 buffer.getWriter32()->writeMatrix(*(SkMatrix*)obj);
(...skipping 24 matching lines...) Expand all
717 static void flattenRegion(SkOrderedWriteBuffer& buffer, const void* obj) { 773 static void flattenRegion(SkOrderedWriteBuffer& buffer, const void* obj) {
718 buffer.getWriter32()->writeRegion(*(SkRegion*)obj); 774 buffer.getWriter32()->writeRegion(*(SkRegion*)obj);
719 } 775 }
720 776
721 static void unflattenRegion(SkOrderedReadBuffer& buffer, void* obj) { 777 static void unflattenRegion(SkOrderedReadBuffer& buffer, void* obj) {
722 buffer.getReader32()->readRegion((SkRegion*)obj); 778 buffer.getReader32()->readRegion((SkRegion*)obj);
723 } 779 }
724 }; 780 };
725 781
726 #endif 782 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698