Upstream version 9.37.197.0
[platform/framework/web/crosswalk.git] / src / third_party / angle / src / libGLESv2 / renderer / d3d9 / VertexDeclarationCache.cpp
1 #include "precompiled.h"
2 //
3 // Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
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 // VertexDeclarationCache.cpp: Implements a helper class to construct and cache vertex declarations.
9
10 #include "libGLESv2/ProgramBinary.h"
11 #include "libGLESv2/VertexAttribute.h"
12 #include "libGLESv2/renderer/d3d9/VertexBuffer9.h"
13 #include "libGLESv2/renderer/d3d9/VertexDeclarationCache.h"
14 #include "libGLESv2/renderer/d3d9/formatutils9.h"
15
16 namespace rx
17 {
18
19 VertexDeclarationCache::VertexDeclarationCache() : mMaxLru(0)
20 {
21     for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
22     {
23         mVertexDeclCache[i].vertexDeclaration = NULL;
24         mVertexDeclCache[i].lruCount = 0;
25     }
26
27     for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
28     {
29         mAppliedVBs[i].serial = 0;
30     }
31
32     mLastSetVDecl = NULL;
33     mInstancingEnabled = true;
34 }
35
36 VertexDeclarationCache::~VertexDeclarationCache()
37 {
38     for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
39     {
40         SafeRelease(mVertexDeclCache[i].vertexDeclaration);
41     }
42 }
43
44 GLenum VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], gl::ProgramBinary *programBinary, GLsizei instances, GLsizei *repeatDraw)
45 {
46     *repeatDraw = 1;
47
48     int indexedAttribute = gl::MAX_VERTEX_ATTRIBS;
49     int instancedAttribute = gl::MAX_VERTEX_ATTRIBS;
50
51     if (instances > 0)
52     {
53         // Find an indexed attribute to be mapped to D3D stream 0
54         for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
55         {
56             if (attributes[i].active)
57             {
58                 if (indexedAttribute == gl::MAX_VERTEX_ATTRIBS && attributes[i].divisor == 0)
59                 {
60                     indexedAttribute = i;
61                 }
62                 else if (instancedAttribute == gl::MAX_VERTEX_ATTRIBS && attributes[i].divisor != 0)
63                 {
64                     instancedAttribute = i;
65                 }
66                 if (indexedAttribute != gl::MAX_VERTEX_ATTRIBS && instancedAttribute != gl::MAX_VERTEX_ATTRIBS)
67                     break;   // Found both an indexed and instanced attribute
68             }
69         }
70
71         if (indexedAttribute == gl::MAX_VERTEX_ATTRIBS)
72         {
73             return GL_INVALID_OPERATION;
74         }
75     }
76
77     D3DVERTEXELEMENT9 elements[gl::MAX_VERTEX_ATTRIBS + 1];
78     D3DVERTEXELEMENT9 *element = &elements[0];
79
80     for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
81     {
82         if (attributes[i].active)
83         {
84             // Directly binding the storage buffer is not supported for d3d9
85             ASSERT(attributes[i].storage == NULL);
86
87             int stream = i;
88
89             if (instances > 0)
90             {
91                 // Due to a bug on ATI cards we can't enable instancing when none of the attributes are instanced.
92                 if (instancedAttribute == gl::MAX_VERTEX_ATTRIBS)
93                 {
94                     *repeatDraw = instances;
95                 }
96                 else
97                 {
98                     if (i == indexedAttribute)
99                     {
100                         stream = 0;
101                     }
102                     else if (i == 0)
103                     {
104                         stream = indexedAttribute;
105                     }
106
107                     UINT frequency = 1;
108                     
109                     if (attributes[i].divisor == 0)
110                     {
111                         frequency = D3DSTREAMSOURCE_INDEXEDDATA | instances;
112                     }
113                     else
114                     {
115                         frequency = D3DSTREAMSOURCE_INSTANCEDATA | attributes[i].divisor;
116                     }
117                     
118                     device->SetStreamSourceFreq(stream, frequency);
119                     mInstancingEnabled = true;
120                 }
121             }
122
123             VertexBuffer9 *vertexBuffer = VertexBuffer9::makeVertexBuffer9(attributes[i].vertexBuffer);
124
125             if (mAppliedVBs[stream].serial != attributes[i].serial ||
126                 mAppliedVBs[stream].stride != attributes[i].stride ||
127                 mAppliedVBs[stream].offset != attributes[i].offset)
128             {
129                 device->SetStreamSource(stream, vertexBuffer->getBuffer(), attributes[i].offset, attributes[i].stride);
130                 mAppliedVBs[stream].serial = attributes[i].serial;
131                 mAppliedVBs[stream].stride = attributes[i].stride;
132                 mAppliedVBs[stream].offset = attributes[i].offset;
133             }
134
135             gl::VertexFormat vertexFormat(*attributes[i].attribute, GL_FLOAT);
136
137             element->Stream = stream;
138             element->Offset = 0;
139             element->Type = d3d9::GetNativeVertexFormat(vertexFormat);
140             element->Method = D3DDECLMETHOD_DEFAULT;
141             element->Usage = D3DDECLUSAGE_TEXCOORD;
142             element->UsageIndex = programBinary->getSemanticIndex(i);
143             element++;
144         }
145     }
146
147     if (instances == 0 || instancedAttribute == gl::MAX_VERTEX_ATTRIBS)
148     {
149         if (mInstancingEnabled)
150         {
151             for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
152             {
153                 device->SetStreamSourceFreq(i, 1);
154             }
155
156             mInstancingEnabled = false;
157         }
158     }
159
160     static const D3DVERTEXELEMENT9 end = D3DDECL_END();
161     *(element++) = end;
162
163     for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
164     {
165         VertexDeclCacheEntry *entry = &mVertexDeclCache[i];
166         if (memcmp(entry->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9)) == 0 && entry->vertexDeclaration)
167         {
168             entry->lruCount = ++mMaxLru;
169             if(entry->vertexDeclaration != mLastSetVDecl)
170             {
171                 device->SetVertexDeclaration(entry->vertexDeclaration);
172                 mLastSetVDecl = entry->vertexDeclaration;
173             }
174
175             return GL_NO_ERROR;
176         }
177     }
178
179     VertexDeclCacheEntry *lastCache = mVertexDeclCache;
180
181     for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
182     {
183         if (mVertexDeclCache[i].lruCount < lastCache->lruCount)
184         {
185             lastCache = &mVertexDeclCache[i];
186         }
187     }
188
189     if (lastCache->vertexDeclaration != NULL)
190     {
191         SafeRelease(lastCache->vertexDeclaration);
192         // mLastSetVDecl is set to the replacement, so we don't have to worry
193         // about it.
194     }
195
196     memcpy(lastCache->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9));
197     device->CreateVertexDeclaration(elements, &lastCache->vertexDeclaration);
198     device->SetVertexDeclaration(lastCache->vertexDeclaration);
199     mLastSetVDecl = lastCache->vertexDeclaration;
200     lastCache->lruCount = ++mMaxLru;
201
202     return GL_NO_ERROR;
203 }
204
205 void VertexDeclarationCache::markStateDirty()
206 {
207     for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
208     {
209         mAppliedVBs[i].serial = 0;
210     }
211
212     mLastSetVDecl = NULL;
213     mInstancingEnabled = true;   // Forces it to be disabled when not used
214 }
215
216 }