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

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

Issue 21564008: use SkTDynamicHash in picture recording (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: smaller default size Created 7 years, 4 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
« no previous file with comments | « no previous file | src/core/SkPictureFlat.cpp » ('j') | src/core/SkTDynamicHash.h » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
11 //#define SK_DEBUG_SIZE 11 //#define SK_DEBUG_SIZE
12 12
13 #include "SkChunkAlloc.h" 13 #include "SkChunkAlloc.h"
14 #include "SkBitmap.h" 14 #include "SkBitmap.h"
15 #include "SkBitmapHeap.h" 15 #include "SkBitmapHeap.h"
16 #include "SkOrderedReadBuffer.h" 16 #include "SkOrderedReadBuffer.h"
17 #include "SkOrderedWriteBuffer.h" 17 #include "SkOrderedWriteBuffer.h"
18 #include "SkPicture.h" 18 #include "SkPicture.h"
19 #include "SkPtrRecorder.h" 19 #include "SkPtrRecorder.h"
20 #include "SkMatrix.h" 20 #include "SkMatrix.h"
21 #include "SkPaint.h" 21 #include "SkPaint.h"
22 #include "SkPath.h" 22 #include "SkPath.h"
23 #include "SkRegion.h" 23 #include "SkRegion.h"
24 #include "SkTRefArray.h" 24 #include "SkTRefArray.h"
25 #include "SkTSearch.h" 25 #include "SkTSearch.h"
26 26
27 #include "SkChecksum.h"
28 #include "SkTDynamicHash.h"
29
27 enum DrawType { 30 enum DrawType {
28 UNUSED, 31 UNUSED,
29 CLIP_PATH, 32 CLIP_PATH,
30 CLIP_REGION, 33 CLIP_REGION,
31 CLIP_RECT, 34 CLIP_RECT,
32 CLIP_RRECT, 35 CLIP_RRECT,
33 CONCAT, 36 CONCAT,
34 DRAW_BITMAP, 37 DRAW_BITMAP,
35 DRAW_BITMAP_MATRIX, 38 DRAW_BITMAP_MATRIX,
36 DRAW_BITMAP_NINE, 39 DRAW_BITMAP_NINE,
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after
256 SkRefCntSet* fTypefaceSet; 259 SkRefCntSet* fTypefaceSet;
257 SkTypefacePlayback* fTypefacePlayback; 260 SkTypefacePlayback* fTypefacePlayback;
258 SkNamedFactorySet* fFactorySet; 261 SkNamedFactorySet* fFactorySet;
259 uint32_t fWriteBufferFlags; 262 uint32_t fWriteBufferFlags;
260 263
261 typedef SkRefCnt INHERITED; 264 typedef SkRefCnt INHERITED;
262 }; 265 };
263 266
264 class SkFlatData { 267 class SkFlatData {
265 public: 268 public:
266 /** 269 // Flatten obj into an SkFlatData with this index. controller owns the SkFl atData*.
267 * Compare two SkFlatData ptrs, returning -1, 0, 1 to allow them to be 270 static SkFlatData* Create(SkFlatController* controller,
268 * sorted. 271 const void* obj,
269 * 272 int index,
270 * Note: this assumes that a and b have different sentinel values, either
271 * InCache or AsCandidate, otherwise the loop will go beyond the end of
272 * the buffers.
273 *
274 * dataToCompare() returns 2 fields before the flattened data:
275 * - checksum
276 * - size
277 * This ensures that if we see two blocks of different length, we will
278 * notice that right away, and not read any further. It also ensures that
279 * we see the checksum right away, so that most of the time it is enough
280 * to short-circuit our comparison.
281 */
282 static int Compare(const SkFlatData& a, const SkFlatData& b) {
283 const uint32_t* stop = a.dataStop();
284 const uint32_t* a_ptr = a.dataToCompare() - 1;
285 const uint32_t* b_ptr = b.dataToCompare() - 1;
286 // We use -1 above, so we can pre-increment our pointers in the loop
287 while (*++a_ptr == *++b_ptr) {}
288
289 if (a_ptr == stop) { // sentinel
290 SkASSERT(b.dataStop() == b_ptr);
291 return 0;
292 }
293 SkASSERT(a_ptr < a.dataStop());
294 SkASSERT(b_ptr < b.dataStop());
295 return (*a_ptr < *b_ptr) ? -1 : 1;
296 }
297
298 // Adapts Compare to be used with SkTSearch
299 static bool Less(const SkFlatData& a, const SkFlatData& b) {
300 return Compare(a, b) < 0;
301 }
302
303 int index() const { return fIndex; }
304 const void* data() const { return (const char*)this + sizeof(*this); }
305 void* data() { return (char*)this + sizeof(*this); }
306 // Our data is always 32bit aligned, so we can offer this accessor
307 uint32_t* data32() { return (uint32_t*)this->data(); }
308 // Returns the size of the flattened data.
309 size_t flatSize() const { return fFlatSize; }
310
311 void setSentinelInCache() {
312 this->setSentinel(kInCache_Sentinel);
313 }
314 void setSentinelAsCandidate() {
315 this->setSentinel(kCandidate_Sentinel);
316 }
317
318 uint32_t checksum() const { return fChecksum; }
319
320 #ifdef SK_DEBUG_SIZE
321 // returns the logical size of our data. Does not return any sentinel or
322 // padding we might have.
323 size_t size() const {
324 return sizeof(SkFlatData) + fFlatSize;
325 }
326 #endif
327
328 static SkFlatData* Create(SkFlatController* controller, const void* obj, int index,
329 void (*flattenProc)(SkOrderedWriteBuffer&, const v oid*)); 273 void (*flattenProc)(SkOrderedWriteBuffer&, const v oid*));
330 274
275 // Unflatten this into result, using bitmapHeap and facePlayback for bitmaps and fonts if given.
331 void unflatten(void* result, 276 void unflatten(void* result,
332 void (*unflattenProc)(SkOrderedReadBuffer&, void*), 277 void (*unflattenProc)(SkOrderedReadBuffer&, void*),
333 SkBitmapHeap* bitmapHeap = NULL, 278 SkBitmapHeap* bitmapHeap = NULL,
334 SkTypefacePlayback* facePlayback = NULL) const; 279 SkTypefacePlayback* facePlayback = NULL) const;
335 280
336 // When we purge an entry, we want to reuse an old index for the new entry, 281 // Do these contain the same data? Ignores index() and topBot().
337 // so we expose this setter. 282 bool operator==(const SkFlatData& that) const {
338 void setIndex(int index) { fIndex = index; } 283 if (this->checksum() != that.checksum()) return false;
339 284 if (this->flatSize() != that.flatSize()) return false;
340 // for unittesting 285 return memcmp(this->data(), that.data(), this->flatSize()) == 0;
341 friend bool operator==(const SkFlatData& a, const SkFlatData& b) {
342 size_t N = (const char*)a.dataStop() - (const char*)a.dataToCompare();
343 return !memcmp(a.dataToCompare(), b.dataToCompare(), N);
344 } 286 }
345 287
346 // returns true if fTopBot[] has been recorded 288 int index() const { return fIndex; }
289 const uint8_t* data() const { return (const uint8_t*)this + sizeof(*this); }
290 size_t flatSize() const { return fFlatSize; }
291 uint32_t checksum() const { return fChecksum; }
292
293 // Returns true if fTopBot[] has been recorded.
347 bool isTopBotWritten() const { 294 bool isTopBotWritten() const {
348 return !SkScalarIsNaN(fTopBot[0]); 295 return !SkScalarIsNaN(fTopBot[0]);
349 } 296 }
350 297
351 // Returns fTopBot array, so it can be passed to a routine to compute them. 298 // Returns fTopBot array, so it can be passed to a routine to compute them.
352 // For efficiency, we assert that fTopBot have not been recorded yet. 299 // For efficiency, we assert that fTopBot have not been recorded yet.
353 SkScalar* writableTopBot() const { 300 SkScalar* writableTopBot() const {
354 SkASSERT(!this->isTopBotWritten()); 301 SkASSERT(!this->isTopBotWritten());
355 return fTopBot; 302 return fTopBot;
356 } 303 }
357 304
358 // return the topbot[] after it has been recorded 305 // Return the topbot[] after it has been recorded.
359 const SkScalar* topBot() const { 306 const SkScalar* topBot() const {
360 SkASSERT(this->isTopBotWritten()); 307 SkASSERT(this->isTopBotWritten());
361 return fTopBot; 308 return fTopBot;
362 } 309 }
363 310
364 private: 311 private:
365 // This is *not* part of the key for search/sort 312 // For SkTDynamicHash
366 int fIndex; 313 static const SkFlatData& Identity(const SkFlatData& flat) { return flat; }
314 static uint32_t Hash(const SkFlatData& flat) { return flat.checksum(); }
315 static bool Equal(const SkFlatData& a, const SkFlatData& b) { return a == b; }
367 316
368 // Cache of paint's FontMetrics fTop,fBottom 317 void setIndex(int index) { fIndex = index; }
369 // initialied to [NaN,NaN] as a sentinel that they have not been recorded ye t 318 uint8_t* data() { return (uint8_t*)this + sizeof(*this); }
370 //
371 // This is *not* part of the key for search/sort
372 mutable SkScalar fTopBot[2];
373 319
374 // marks fTopBot[] as unrecorded 320 // This assumes the payload flat data has already been written and does not modify it.
375 void setTopBotUnwritten() { 321 void stampHeader(int index, int32_t size) {
376 this->fTopBot[0] = SK_ScalarNaN; // initial to sentinel values 322 SkASSERT(SkIsAlign4(size));
323 fIndex = index;
324 fFlatSize = size;
325 fTopBot[0] = SK_ScalarNaN; // Mark as unwritten.
326 fChecksum = SkChecksum::Compute((uint32_t*)this->data(), size);
377 } 327 }
378 328
379 // From here down is the data we look at in the search/sort. We always begin 329 template <class T> friend class SkFlatDictionary;
380 // with the checksum and then length. 330
331 int fIndex;
332 int32_t fFlatSize;
381 uint32_t fChecksum; 333 uint32_t fChecksum;
382 int32_t fFlatSize; // size of flattened data 334 mutable SkScalar fTopBot[2]; // Cache of FontMetrics fTop, fBottom. Starts as [NaN,?].
383 // uint32_t flattenedData[] 335 // uint32_t flattenedData[] implicitly hangs off the end.
384 // uint32_t sentinelValue
385
386 const uint32_t* dataToCompare() const {
387 return (const uint32_t*)&fChecksum;
388 }
389 const uint32_t* dataStop() const {
390 SkASSERT(SkIsAlign4(fFlatSize));
391 return (const uint32_t*)((const char*)this->data() + fFlatSize);
392 }
393
394 enum {
395 kInCache_Sentinel = 0,
396 kCandidate_Sentinel = ~0U,
397 };
398 void setSentinel(uint32_t value) {
399 SkASSERT(SkIsAlign4(fFlatSize));
400 this->data32()[fFlatSize >> 2] = value;
401 }
402
403 // This does not modify the payload flat data, in case it's already been wri tten.
404 void stampHeaderAndSentinel(int index, int32_t size);
405 template <class T> friend class SkFlatDictionary; // For stampHeaderAndSent inel().
406 }; 336 };
407 337
408 template <class T> 338 template <class T>
409 class SkFlatDictionary { 339 class SkFlatDictionary {
410 static const size_t kWriteBufferGrowthBytes = 1024; 340 static const size_t kWriteBufferGrowthBytes = 1024;
411 341
412 public: 342 public:
413 SkFlatDictionary(SkFlatController* controller, size_t scratchSizeGuess = 0) 343 SkFlatDictionary(SkFlatController* controller, size_t scratchSizeGuess = 0)
414 : fFlattenProc(NULL) 344 : fFlattenProc(NULL)
415 , fUnflattenProc(NULL) 345 , fUnflattenProc(NULL)
416 , fController(SkRef(controller)) 346 , fController(SkRef(controller))
417 , fScratchSize(scratchSizeGuess) 347 , fScratchSize(scratchSizeGuess)
418 , fScratch(AllocScratch(fScratchSize)) 348 , fScratch(AllocScratch(fScratchSize))
419 , fWriteBuffer(kWriteBufferGrowthBytes) 349 , fWriteBuffer(kWriteBufferGrowthBytes)
420 , fWriteBufferReady(false) 350 , fWriteBufferReady(false) {
421 , fNextIndex(1) { // set to 1 since returning a zero from find() indicates failure 351 this->reset();
422 sk_bzero(fHash, sizeof(fHash)); 352 }
353
354 /**
355 * Clears the dictionary of all entries. However, it does NOT free the
356 * memory that was allocated for each entry (that's owned by controller).
357 */
358 void reset() {
359 fIndexed.rewind();
360 // TODO(mtklein): There's no reason to have the index start from 1. Cle an this up.
423 // index 0 is always empty since it is used as a signal that find failed 361 // index 0 is always empty since it is used as a signal that find failed
424 fIndexedData.push(NULL); 362 fIndexed.push(NULL);
363 fNextIndex = 1;
425 } 364 }
426 365
427 ~SkFlatDictionary() { 366 ~SkFlatDictionary() {
428 sk_free(fScratch); 367 sk_free(fScratch);
429 } 368 }
430 369
431 int count() const { 370 int count() const {
432 SkASSERT(fIndexedData.count() == fSortedData.count()+1); 371 return fIndexed.count() - 1;
433 return fSortedData.count();
434 } 372 }
435 373
436 const SkFlatData* operator[](int index) const { 374 // For testing only. Index is zero-based.
437 SkASSERT(index >= 0 && index < fSortedData.count()); 375 const SkFlatData* operator[](int index) {
438 return fSortedData[index]; 376 return fIndexed[index+1];
439 } 377 }
440 378
441 /** 379 /**
442 * Clears the dictionary of all entries. However, it does NOT free the 380 * Given an element of type T return its 1-based index in the dictionary. If
443 * memory that was allocated for each entry. 381 * the element wasn't previously in the dictionary it is automatically
382 * added.
383 *
444 */ 384 */
445 void reset() { 385 int find(const T& element) {
446 fSortedData.reset(); 386 return this->findAndReturnFlat(element)->index();
447 fIndexedData.rewind();
448 // index 0 is always empty since it is used as a signal that find failed
449 fIndexedData.push(NULL);
450 fNextIndex = 1;
451 sk_bzero(fHash, sizeof(fHash));
452 } 387 }
453 388
454 /** 389 /**
455 * Similar to find. Allows the caller to specify an SkFlatData to replace in 390 * Similar to find. Allows the caller to specify an SkFlatData to replace in
456 * the case of an add. Also tells the caller whether a new SkFlatData was 391 * the case of an add. Also tells the caller whether a new SkFlatData was
457 * added and whether the old one was replaced. The parameters added and 392 * added and whether the old one was replaced. The parameters added and
458 * replaced are required to be non-NULL. Rather than returning the index of 393 * replaced are required to be non-NULL. Rather than returning the index of
459 * the entry in the dictionary, it returns the actual SkFlatData. 394 * the entry in the dictionary, it returns the actual SkFlatData.
460 */ 395 */
461 const SkFlatData* findAndReplace(const T& element, 396 const SkFlatData* findAndReplace(const T& element,
462 const SkFlatData* toReplace, bool* added, 397 const SkFlatData* toReplace,
398 bool* added,
463 bool* replaced) { 399 bool* replaced) {
464 SkASSERT(added != NULL && replaced != NULL); 400 SkASSERT(added != NULL && replaced != NULL);
465 int oldCount = fSortedData.count(); 401
466 const SkFlatData* flat = this->findAndReturnFlat(element); 402 const int oldCount = this->count();
467 *added = fSortedData.count() == oldCount + 1; 403 SkFlatData* flat = this->findAndReturnMutableFlat(element);
468 *replaced = false; 404 *added = this->count() > oldCount;
469 if (*added && toReplace != NULL) { 405
470 // First, find the index of the one to replace 406 // If we don't want to replace anything, we're done.
471 int indexToReplace = fSortedData.find(toReplace); 407 if (!*added || toReplace == NULL) {
472 if (indexToReplace >= 0) { 408 *replaced = false;
473 // findAndReturnFlat set the index to fNextIndex and increased 409 return flat;
474 // fNextIndex by one. Reuse the index from the one being
475 // replaced and reset fNextIndex to the proper value.
476 int oldIndex = flat->index();
477 const_cast<SkFlatData*>(flat)->setIndex(toReplace->index());
478 fIndexedData[toReplace->index()] = flat;
479 fNextIndex--;
480 // Remove from the arrays.
481 fSortedData.remove(indexToReplace);
482 fIndexedData.remove(oldIndex);
483 // Remove from the hash table.
484 int oldHash = ChecksumToHashIndex(toReplace->checksum());
485 if (fHash[oldHash] == toReplace) {
486 fHash[oldHash] = NULL;
487 }
488 // Delete the actual object.
489 fController->unalloc((void*)toReplace);
490 *replaced = true;
491 SkASSERT(fIndexedData.count() == fSortedData.count()+1);
492 }
493 } 410 }
411
412 // If we don't have the thing to replace, we're done.
413 const SkFlatData* found = fHash.find(*toReplace);
414 if (found == NULL) {
415 *replaced = false;
416 return flat;
417 }
418
419 // We can replace found with flat. First we have to set fNextIndex and fIndexed back
420 // to where they were before findAndReturnMutableFlat changed them.
421 fIndexed.remove(flat->index());
422 fNextIndex--;
423
424 // Do the replacement.
425 flat->setIndex(found->index());
426 fIndexed[flat->index()] = flat;
427 fHash.remove(*found);
428 fController->unalloc((void*)found);
429 SkASSERT(this->count() == oldCount);
430
431 *replaced = true;
494 return flat; 432 return flat;
495 } 433 }
496 434
497 /** 435 /**
498 * Given an element of type T return its 1-based index in the dictionary. If
499 * the element wasn't previously in the dictionary it is automatically
500 * added.
501 *
502 * To make the Compare function fast, we write a sentinel value at the end
503 * of each block. The blocks in our fSortedData[] all have a 0 sentinel. The
504 * newly created block we're comparing against has a -1 in the sentinel.
505 *
506 * This trick allows Compare to always loop until failure. If it fails on
507 * the sentinal value, we know the blocks are equal.
508 */
509 int find(const T& element) {
510 return this->findAndReturnFlat(element)->index();
511 }
512
513 /**
514 * Unflatten the objects and return them in SkTRefArray, or return NULL 436 * Unflatten the objects and return them in SkTRefArray, or return NULL
515 * if there no objects (instead of an empty array). 437 * if there no objects. Caller takes ownership of result.
516 */ 438 */
517 SkTRefArray<T>* unflattenToArray() const { 439 SkTRefArray<T>* unflattenToArray() const {
518 int count = fSortedData.count(); 440 const int count = this->count();
519 SkTRefArray<T>* array = NULL; 441 if (count == 0) {
520 if (count > 0) { 442 return NULL;
521 array = SkTRefArray<T>::Create(count); 443 }
522 this->unflattenIntoArray(&array->writableAt(0)); 444 SkTRefArray<T>* array = SkTRefArray<T>::Create(count);
445 for (int i = 0; i < count; i++) {
446 this->unflatten(&array->writableAt(i), fIndexed[i+1]);
523 } 447 }
524 return array; 448 return array;
525 } 449 }
526 450
527 /** 451 /**
528 * Unflatten the specific object at the given index 452 * Unflatten the specific object at the given index.
453 * Caller takes ownership of the result.
529 */ 454 */
530 T* unflatten(int index) const { 455 T* unflatten(int index) const {
531 SkASSERT(fIndexedData.count() == fSortedData.count()+1); 456 const SkFlatData* element = fIndexed[index];
532 const SkFlatData* element = fIndexedData[index];
533 SkASSERT(index == element->index()); 457 SkASSERT(index == element->index());
534 458
535 T* dst = new T; 459 T* dst = new T;
536 this->unflatten(dst, element); 460 this->unflatten(dst, element);
537 return dst; 461 return dst;
538 } 462 }
539 463
464 /**
465 * Find or insert a flattened version of element into the dictionary.
466 * Caller does not take ownership of the result.
467 */
540 const SkFlatData* findAndReturnFlat(const T& element) { 468 const SkFlatData* findAndReturnFlat(const T& element) {
541 // Only valid until the next call to resetScratch(). 469 return this->findAndReturnMutableFlat(element);
542 const SkFlatData& scratch = this->resetScratch(element, fNextIndex);
543
544 // See if we have it in the hash?
545 const int hashIndex = ChecksumToHashIndex(scratch.checksum());
546 const SkFlatData* candidate = fHash[hashIndex];
547 if (candidate != NULL && SkFlatData::Compare(scratch, *candidate) == 0) {
548 return candidate;
549 }
550
551 // See if we have it at all?
552 const int index = SkTSearch<const SkFlatData, SkFlatData::Less>(fSortedD ata.begin(),
553 fSortedD ata.count(),
554 &scratch ,
555 sizeof(& scratch));
556 if (index >= 0) {
557 // Found. Update hash before we return.
558 fHash[hashIndex] = fSortedData[index];
559 return fSortedData[index];
560 }
561
562 // We don't have it. Add it.
563 SkFlatData* detached = this->detachScratch();
564 // detached will live beyond the next call to resetScratch(), but is own ed by fController.
565 *fSortedData.insert(~index) = detached; // SkTSearch returned bit-not o f where to insert.
566 *fIndexedData.insert(detached->index()) = detached;
567 fHash[hashIndex] = detached;
568
569 SkASSERT(detached->index() == fNextIndex);
570 SkASSERT(fSortedData.count() == fNextIndex);
571 SkASSERT(fIndexedData.count() == fNextIndex+1);
572 fNextIndex++;
573
574 return detached;
575 } 470 }
576 471
577 protected: 472 protected:
578 void (*fFlattenProc)(SkOrderedWriteBuffer&, const void*); 473 void (*fFlattenProc)(SkOrderedWriteBuffer&, const void*);
579 void (*fUnflattenProc)(SkOrderedReadBuffer&, void*); 474 void (*fUnflattenProc)(SkOrderedReadBuffer&, void*);
580 475
581 private: 476 private:
582 // Layout: [ SkFlatData header, 20 bytes ] [ data ..., 4-byte aligned ] [ se ntinel, 4 bytes] 477 // Layout: [ SkFlatData header, 20 bytes ] [ data ..., 4-byte aligned ]
583 static size_t SizeWithPadding(size_t flatDataSize) { 478 static size_t SizeWithPadding(size_t flatDataSize) {
584 SkASSERT(SkIsAlign4(flatDataSize)); 479 SkASSERT(SkIsAlign4(flatDataSize));
585 return sizeof(SkFlatData) + flatDataSize + sizeof(uint32_t); 480 return sizeof(SkFlatData) + flatDataSize;
586 } 481 }
587 482
588 // Allocate a new scratch SkFlatData. Must be sk_freed. 483 // Allocate a new scratch SkFlatData. Must be sk_freed.
589 static SkFlatData* AllocScratch(size_t scratchSize) { 484 static SkFlatData* AllocScratch(size_t scratchSize) {
590 return (SkFlatData*) sk_malloc_throw(SizeWithPadding(scratchSize)); 485 return (SkFlatData*) sk_malloc_throw(SizeWithPadding(scratchSize));
591 } 486 }
592 487
593 // We have to delay fWriteBuffer's initialization until its first use; fCont roller might not 488 // We have to delay fWriteBuffer's initialization until its first use; fCont roller might not
594 // be fully set up by the time we get it in the constructor. 489 // be fully set up by the time we get it in the constructor.
595 void lazyWriteBufferInit() { 490 void lazyWriteBufferInit() {
596 if (fWriteBufferReady) { 491 if (fWriteBufferReady) {
597 return; 492 return;
598 } 493 }
599 // Without a bitmap heap, we'll flatten bitmaps into paints. That's nev er what you want. 494 // Without a bitmap heap, we'll flatten bitmaps into paints. That's nev er what you want.
600 SkASSERT(fController->getBitmapHeap() != NULL); 495 SkASSERT(fController->getBitmapHeap() != NULL);
601 fWriteBuffer.setBitmapHeap(fController->getBitmapHeap()); 496 fWriteBuffer.setBitmapHeap(fController->getBitmapHeap());
602 fWriteBuffer.setTypefaceRecorder(fController->getTypefaceSet()); 497 fWriteBuffer.setTypefaceRecorder(fController->getTypefaceSet());
603 fWriteBuffer.setNamedFactoryRecorder(fController->getNamedFactorySet()); 498 fWriteBuffer.setNamedFactoryRecorder(fController->getNamedFactorySet());
604 fWriteBuffer.setFlags(fController->getWriteBufferFlags()); 499 fWriteBuffer.setFlags(fController->getWriteBufferFlags());
605 fWriteBufferReady = true; 500 fWriteBufferReady = true;
606 } 501 }
607 502
503 SkFlatData* findAndReturnMutableFlat(const T& element) {
504 // Only valid until the next call to resetScratch().
505 const SkFlatData& scratch = this->resetScratch(element, fNextIndex);
506
507 SkFlatData* candidate = fHash.find(scratch);
508 if (candidate != NULL) return candidate;
509
510 SkFlatData* detached = this->detachScratch();
511 fHash.add(detached);
512 *fIndexed.insert(fNextIndex) = detached;
513 fNextIndex++;
514 return detached;
515 }
516
608 // This reference is valid only until the next call to resetScratch() or det achScratch(). 517 // This reference is valid only until the next call to resetScratch() or det achScratch().
609 const SkFlatData& resetScratch(const T& element, int index) { 518 const SkFlatData& resetScratch(const T& element, int index) {
610 this->lazyWriteBufferInit(); 519 this->lazyWriteBufferInit();
611 520
612 // Flatten element into fWriteBuffer (using fScratch as storage). 521 // Flatten element into fWriteBuffer (using fScratch as storage).
613 fWriteBuffer.reset(fScratch->data(), fScratchSize); 522 fWriteBuffer.reset(fScratch->data(), fScratchSize);
614 fFlattenProc(fWriteBuffer, &element); 523 fFlattenProc(fWriteBuffer, &element);
615 const size_t bytesWritten = fWriteBuffer.bytesWritten(); 524 const size_t bytesWritten = fWriteBuffer.bytesWritten();
616 525
617 // If all the flattened bytes fit into fScratch, we can skip a call to w riteToMemory. 526 // If all the flattened bytes fit into fScratch, we can skip a call to w riteToMemory.
618 if (!fWriteBuffer.wroteOnlyToStorage()) { 527 if (!fWriteBuffer.wroteOnlyToStorage()) {
619 SkASSERT(bytesWritten > fScratchSize); 528 SkASSERT(bytesWritten > fScratchSize);
620 // It didn't all fit. Copy into a larger replacement SkFlatData. 529 // It didn't all fit. Copy into a larger replacement SkFlatData.
621 // We can't just realloc because it might move the pointer and confu se writeToMemory. 530 // We can't just realloc because it might move the pointer and confu se writeToMemory.
622 SkFlatData* larger = AllocScratch(bytesWritten); 531 SkFlatData* larger = AllocScratch(bytesWritten);
623 fWriteBuffer.writeToMemory(larger->data()); 532 fWriteBuffer.writeToMemory(larger->data());
624 533
625 // Carry on with this larger scratch to minimize the likelihood of f uture resizing. 534 // Carry on with this larger scratch to minimize the likelihood of f uture resizing.
626 sk_free(fScratch); 535 sk_free(fScratch);
627 fScratchSize = bytesWritten; 536 fScratchSize = bytesWritten;
628 fScratch = larger; 537 fScratch = larger;
629 } 538 }
630 539
631 // The data is in fScratch now, but we need to stamp its header and trai ling sentinel. 540 // The data is in fScratch now but we need to stamp its header.
632 fScratch->stampHeaderAndSentinel(index, bytesWritten); 541 fScratch->stampHeader(index, bytesWritten);
633 return *fScratch; 542 return *fScratch;
634 } 543 }
635 544
636 // This result is owned by fController and lives as long as it does (unless unalloc'd). 545 // This result is owned by fController and lives as long as it does (unless unalloc'd).
637 SkFlatData* detachScratch() { 546 SkFlatData* detachScratch() {
638 // Allocate a new SkFlatData exactly big enough to hold our current scra tch. 547 // Allocate a new SkFlatData exactly big enough to hold our current scra tch.
639 // We use the controller for this allocation to extend the allocation's lifetime and allow 548 // We use the controller for this allocation to extend the allocation's lifetime and allow
640 // the controller to do whatever memory management it wants. 549 // the controller to do whatever memory management it wants.
641 const size_t paddedSize = SizeWithPadding(fScratch->flatSize()); 550 const size_t paddedSize = SizeWithPadding(fScratch->flatSize());
642 SkFlatData* detached = (SkFlatData*)fController->allocThrow(paddedSize); 551 SkFlatData* detached = (SkFlatData*)fController->allocThrow(paddedSize);
643 552
644 // Copy scratch into the new SkFlatData, setting the sentinel for cache storage. 553 // Copy scratch into the new SkFlatData.
645 memcpy(detached, fScratch, paddedSize); 554 memcpy(detached, fScratch, paddedSize);
646 detached->setSentinelInCache();
647 555
648 // We can now reuse fScratch, and detached will live until fController d ies. 556 // We can now reuse fScratch, and detached will live until fController d ies.
649 return detached; 557 return detached;
650 } 558 }
651 559
652 void unflatten(T* dst, const SkFlatData* element) const { 560 void unflatten(T* dst, const SkFlatData* element) const {
653 element->unflatten(dst, fUnflattenProc, 561 element->unflatten(dst,
562 fUnflattenProc,
654 fController->getBitmapHeap(), 563 fController->getBitmapHeap(),
655 fController->getTypefacePlayback()); 564 fController->getTypefacePlayback());
656 } 565 }
657 566
658 void unflattenIntoArray(T* array) const { 567 // All SkFlatData* stored in fIndexed and fHash are owned by the controller.
659 const int count = fSortedData.count();
660 SkASSERT(fIndexedData.count() == fSortedData.count()+1);
661 const SkFlatData* const* iter = fSortedData.begin();
662 for (int i = 0; i < count; ++i) {
663 const SkFlatData* element = iter[i];
664 int index = element->index() - 1;
665 SkASSERT((unsigned)index < (unsigned)count);
666 unflatten(&array[index], element);
667 }
668 }
669
670 SkAutoTUnref<SkFlatController> fController; 568 SkAutoTUnref<SkFlatController> fController;
671 size_t fScratchSize; // How many bytes fScratch has allocated for data itse lf. 569 size_t fScratchSize; // How many bytes fScratch has allocated for data itse lf.
672 SkFlatData* fScratch; // Owned, must be freed with sk_free. 570 SkFlatData* fScratch; // Owned, must be freed with sk_free.
673 SkOrderedWriteBuffer fWriteBuffer; 571 SkOrderedWriteBuffer fWriteBuffer;
674 bool fWriteBufferReady; 572 bool fWriteBufferReady;
675 573
676 // SkFlatDictionary has two copies of the data one indexed by the 574 // We map between SkFlatData and a 1-based integer index.
677 // SkFlatData's index and the other sorted. The sorted data is used
678 // for finding and uniquification while the indexed copy is used
679 // for standard array-style lookups based on the SkFlatData's index
680 // (as in 'unflatten').
681 int fNextIndex; 575 int fNextIndex;
682 SkTDArray<const SkFlatData*> fIndexedData;
683 // fSortedData is sorted by checksum/size/data.
684 SkTDArray<const SkFlatData*> fSortedData;
685 576
686 enum { 577 // For index -> SkFlatData. fIndexed[0] is always NULL.
687 // Determined by trying diff values on picture-recording benchmarks 578 SkTDArray<const SkFlatData*> fIndexed;
688 // (e.g. PictureRecordBench.cpp), choosing the smallest value that
689 // showed a big improvement. Even better would be to benchmark diff
690 // values on recording representative web-pages or other "real" content.
691 HASH_BITS = 7,
692 HASH_MASK = (1 << HASH_BITS) - 1,
693 HASH_COUNT = 1 << HASH_BITS
694 };
695 const SkFlatData* fHash[HASH_COUNT];
696 579
697 static int ChecksumToHashIndex(uint32_t checksum) { 580 // For SkFlatData -> cached SkFlatData, which has index().
698 int n = checksum; 581 SkTDynamicHash<SkFlatData, SkFlatData,
699 if (HASH_BITS < 32) { 582 SkFlatData::Identity, SkFlatData::Hash, SkFlatData::Equal> fH ash;
700 n ^= n >> 16;
701 }
702 if (HASH_BITS < 16) {
703 n ^= n >> 8;
704 }
705 if (HASH_BITS < 8) {
706 n ^= n >> 4;
707 }
708 return n & HASH_MASK;
709 }
710 }; 583 };
711 584
712 /////////////////////////////////////////////////////////////////////////////// 585 ///////////////////////////////////////////////////////////////////////////////
713 // Some common dictionaries are defined here for both reference and convenience 586 // Some common dictionaries are defined here for both reference and convenience
714 /////////////////////////////////////////////////////////////////////////////// 587 ///////////////////////////////////////////////////////////////////////////////
715 588
716 template <class T> 589 template <class T>
717 static void SkFlattenObjectProc(SkOrderedWriteBuffer& buffer, const void* obj) { 590 static void SkFlattenObjectProc(SkOrderedWriteBuffer& buffer, const void* obj) {
718 ((T*)obj)->flatten(buffer); 591 ((T*)obj)->flatten(buffer);
719 } 592 }
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
798 static void flattenRegion(SkOrderedWriteBuffer& buffer, const void* obj) { 671 static void flattenRegion(SkOrderedWriteBuffer& buffer, const void* obj) {
799 buffer.getWriter32()->writeRegion(*(SkRegion*)obj); 672 buffer.getWriter32()->writeRegion(*(SkRegion*)obj);
800 } 673 }
801 674
802 static void unflattenRegion(SkOrderedReadBuffer& buffer, void* obj) { 675 static void unflattenRegion(SkOrderedReadBuffer& buffer, void* obj) {
803 buffer.getReader32()->readRegion((SkRegion*)obj); 676 buffer.getReader32()->readRegion((SkRegion*)obj);
804 } 677 }
805 }; 678 };
806 679
807 #endif 680 #endif
OLDNEW
« no previous file with comments | « no previous file | src/core/SkPictureFlat.cpp » ('j') | src/core/SkTDynamicHash.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698