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