Home | History | Annotate | Download | only in gpu
      1 /*
      2  * Copyright 2010 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #ifndef GrVertexWriter_DEFINED
      9 #define GrVertexWriter_DEFINED
     10 
     11 #include "GrQuad.h"
     12 #include "SkTemplates.h"
     13 #include <type_traits>
     14 
     15 /**
     16  * Helper for writing vertex data to a buffer. Usage:
     17  *  GrVertexWriter vertices{target->makeVertexSpace(...)};
     18  *  vertices.write(A0, B0, C0, ...);
     19  *  vertices.write(A1, B1, C1, ...);
     20  *
     21  * Supports any number of arguments. Each argument must be POD (plain old data), or an array
     22  * thereof.
     23  */
     24 struct GrVertexWriter {
     25     void* fPtr;
     26 
     27     template <typename T>
     28     class Conditional {
     29     public:
     30         explicit Conditional(bool condition, const T& value)
     31             : fCondition(condition), fValue(value) {}
     32     private:
     33         friend struct GrVertexWriter;
     34 
     35         bool fCondition;
     36         T fValue;
     37     };
     38 
     39     template <typename T>
     40     static Conditional<T> If(bool condition, const T& value) {
     41         return Conditional<T>(condition, value);
     42     }
     43 
     44     template <typename T>
     45     struct Skip {};
     46 
     47     template <typename T, typename... Args>
     48     void write(const T& val, const Args&... remainder) {
     49         static_assert(std::is_pod<T>::value, "");
     50         // This assert is barely related to what we're trying to check - that our vertex data
     51         // matches our attribute layouts, where each attribute is aligned to four bytes. If this
     52         // becomes a problem, just remove it.
     53         static_assert(alignof(T) <= 4, "");
     54         memcpy(fPtr, &val, sizeof(T));
     55         fPtr = SkTAddOffset<void>(fPtr, sizeof(T));
     56         this->write(remainder...);
     57     }
     58 
     59     template <typename T, size_t N, typename... Args>
     60     void write(const T(&val)[N], const Args&... remainder) {
     61         static_assert(std::is_pod<T>::value, "");
     62         static_assert(alignof(T) <= 4, "");
     63         memcpy(fPtr, val, N * sizeof(T));
     64         fPtr = SkTAddOffset<void>(fPtr, N * sizeof(T));
     65         this->write(remainder...);
     66     }
     67 
     68     template <typename... Args>
     69     void write(const GrVertexColor& color, const Args&... remainder) {
     70         this->write(color.fColor[0]);
     71         if (color.fWideColor) {
     72             this->write(color.fColor[1]);
     73         }
     74         this->write(remainder...);
     75     }
     76 
     77     template <typename T, typename... Args>
     78     void write(const Conditional<T>& val, const Args&... remainder) {
     79         if (val.fCondition) {
     80             this->write(val.fValue);
     81         }
     82         this->write(remainder...);
     83     }
     84 
     85     template <typename T, typename... Args>
     86     void write(const Skip<T>& val, const Args&... remainder) {
     87         fPtr = SkTAddOffset<void>(fPtr, sizeof(T));
     88         this->write(remainder...);
     89     }
     90 
     91     template <typename... Args>
     92     void write(const Sk4f& vector, const Args&... remainder) {
     93         float buffer[4];
     94         vector.store(buffer);
     95         this->write<float, 4>(buffer);
     96         this->write(remainder...);
     97     }
     98 
     99     void write() {}
    100 
    101     /**
    102      * Specialized utility for writing a four-vertices, with some data being replicated at each
    103      * vertex, and other data being the appropriate 2-components from an SkRect to construct a
    104      * triangle strip.
    105      *
    106      * writeQuad(A, B, C, ...) is similar to write(A, B, C, ...), except that:
    107      *
    108      * - Four sets of data will be written
    109      * - For any arguments of type TriStrip, a unique SkPoint will be written at each vertex,
    110      *   in this order: left-top, left-bottom, right-top, right-bottom.
    111      */
    112     template <typename T>
    113     struct TriStrip { T l, t, r, b; };
    114 
    115     static TriStrip<float> TriStripFromRect(const SkRect& r) {
    116         return { r.fLeft, r.fTop, r.fRight, r.fBottom };
    117     }
    118 
    119     template <typename T>
    120     struct TriFan { T l, t, r, b; };
    121 
    122     static TriFan<float> TriFanFromRect(const SkRect& r) {
    123         return { r.fLeft, r.fTop, r.fRight, r.fBottom };
    124     }
    125 
    126     template <typename... Args>
    127     void writeQuad(const Args&... remainder) {
    128         this->writeQuadVert<0>(remainder...);
    129         this->writeQuadVert<1>(remainder...);
    130         this->writeQuadVert<2>(remainder...);
    131         this->writeQuadVert<3>(remainder...);
    132     }
    133 
    134 private:
    135     template <int corner, typename T, typename... Args>
    136     void writeQuadVert(const T& val, const Args&... remainder) {
    137         this->writeQuadValue<corner>(val);
    138         this->writeQuadVert<corner>(remainder...);
    139     }
    140 
    141     template <int corner>
    142     void writeQuadVert() {}
    143 
    144     template <int corner, typename T>
    145     void writeQuadValue(const T& val) {
    146         this->write(val);
    147     }
    148 
    149     template <int corner, typename T>
    150     void writeQuadValue(const TriStrip<T>& r) {
    151         switch (corner) {
    152             case 0: this->write(r.l, r.t); break;
    153             case 1: this->write(r.l, r.b); break;
    154             case 2: this->write(r.r, r.t); break;
    155             case 3: this->write(r.r, r.b); break;
    156         }
    157     }
    158 
    159     template <int corner, typename T>
    160     void writeQuadValue(const TriFan<T>& r) {
    161         switch (corner) {
    162         case 0: this->write(r.l, r.t); break;
    163         case 1: this->write(r.l, r.b); break;
    164         case 2: this->write(r.r, r.b); break;
    165         case 3: this->write(r.r, r.t); break;
    166         }
    167     }
    168 
    169     template <int corner>
    170     void writeQuadValue(const GrQuad& q) {
    171         this->write(q.point(corner));
    172     }
    173 };
    174 
    175 #endif
    176