blob: a65a15811f93cb89433469c96ca3d2bcc5ae4bef [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 {
shannon.woods@transgaming.com51817d42013-01-25 21:55:57 +000059 if (indexedAttribute == gl::MAX_VERTEX_ATTRIBS && attributes[i].divisor == 0)
daniel@transgaming.com70a219b2012-11-28 21:00:08 +000060 {
shannon.woods@transgaming.com51817d42013-01-25 21:55:57 +000061 indexedAttribute = i;
daniel@transgaming.com70a219b2012-11-28 21:00:08 +000062 }
shannon.woods@transgaming.com51817d42013-01-25 21:55:57 +000063 else if (instancedAttribute == gl::MAX_VERTEX_ATTRIBS && attributes[i].divisor != 0)
daniel@transgaming.com70a219b2012-11-28 21:00:08 +000064 {
shannon.woods@transgaming.com51817d42013-01-25 21:55:57 +000065 instancedAttribute = i;
daniel@transgaming.com70a219b2012-11-28 21:00:08 +000066 }
shannon.woods@transgaming.com51817d42013-01-25 21:55:57 +000067 if (indexedAttribute != gl::MAX_VERTEX_ATTRIBS && instancedAttribute != gl::MAX_VERTEX_ATTRIBS)
68 break; // Found both an indexed and instanced attribute
daniel@transgaming.com70a219b2012-11-28 21:00:08 +000069 }
70 }
71
72 if (indexedAttribute == gl::MAX_VERTEX_ATTRIBS)
73 {
74 return GL_INVALID_OPERATION;
75 }
76 }
77
78 D3DVERTEXELEMENT9 elements[gl::MAX_VERTEX_ATTRIBS + 1];
79 D3DVERTEXELEMENT9 *element = &elements[0];
80
81 for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
82 {
83 if (attributes[i].active)
84 {
shannon.woods@transgaming.comdb1899c2013-02-28 23:08:33 +000085 // Directly binding the storage buffer is not supported for d3d9
86 ASSERT(attributes[i].storage == NULL);
87
daniel@transgaming.com70a219b2012-11-28 21:00:08 +000088 int stream = i;
89
90 if (instances > 0)
91 {
92 // Due to a bug on ATI cards we can't enable instancing when none of the attributes are instanced.
93 if (instancedAttribute == gl::MAX_VERTEX_ATTRIBS)
94 {
95 *repeatDraw = instances;
96 }
97 else
98 {
99 if (i == indexedAttribute)
100 {
101 stream = 0;
102 }
103 else if (i == 0)
104 {
105 stream = indexedAttribute;
106 }
107
108 UINT frequency = 1;
109
110 if (attributes[i].divisor == 0)
111 {
112 frequency = D3DSTREAMSOURCE_INDEXEDDATA | instances;
113 }
114 else
115 {
116 frequency = D3DSTREAMSOURCE_INSTANCEDATA | attributes[i].divisor;
117 }
118
119 device->SetStreamSourceFreq(stream, frequency);
120 mInstancingEnabled = true;
121 }
122 }
123
daniel@transgaming.com4150d362012-12-20 21:07:43 +0000124 VertexBuffer9 *vertexBuffer = VertexBuffer9::makeVertexBuffer9(attributes[i].vertexBuffer);
125
daniel@transgaming.com70a219b2012-11-28 21:00:08 +0000126 if (mAppliedVBs[stream].serial != attributes[i].serial ||
127 mAppliedVBs[stream].stride != attributes[i].stride ||
128 mAppliedVBs[stream].offset != attributes[i].offset)
129 {
daniel@transgaming.com4150d362012-12-20 21:07:43 +0000130 device->SetStreamSource(stream, vertexBuffer->getBuffer(), attributes[i].offset, attributes[i].stride);
daniel@transgaming.com70a219b2012-11-28 21:00:08 +0000131 mAppliedVBs[stream].serial = attributes[i].serial;
132 mAppliedVBs[stream].stride = attributes[i].stride;
133 mAppliedVBs[stream].offset = attributes[i].offset;
134 }
135
136 element->Stream = stream;
137 element->Offset = 0;
daniel@transgaming.com4150d362012-12-20 21:07:43 +0000138 element->Type = attributes[i].attribute->mArrayEnabled ? vertexBuffer->getDeclType(*attributes[i].attribute) : D3DDECLTYPE_FLOAT4;
daniel@transgaming.com70a219b2012-11-28 21:00:08 +0000139 element->Method = D3DDECLMETHOD_DEFAULT;
140 element->Usage = D3DDECLUSAGE_TEXCOORD;
141 element->UsageIndex = programBinary->getSemanticIndex(i);
142 element++;
143 }
144 }
145
146 if (instances == 0 || instancedAttribute == gl::MAX_VERTEX_ATTRIBS)
147 {
148 if (mInstancingEnabled)
149 {
150 for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
151 {
152 device->SetStreamSourceFreq(i, 1);
153 }
154
155 mInstancingEnabled = false;
156 }
157 }
158
159 static const D3DVERTEXELEMENT9 end = D3DDECL_END();
160 *(element++) = end;
161
162 for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
163 {
164 VertexDeclCacheEntry *entry = &mVertexDeclCache[i];
165 if (memcmp(entry->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9)) == 0 && entry->vertexDeclaration)
166 {
167 entry->lruCount = ++mMaxLru;
168 if(entry->vertexDeclaration != mLastSetVDecl)
169 {
170 device->SetVertexDeclaration(entry->vertexDeclaration);
171 mLastSetVDecl = entry->vertexDeclaration;
172 }
173
174 return GL_NO_ERROR;
175 }
176 }
177
178 VertexDeclCacheEntry *lastCache = mVertexDeclCache;
179
180 for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
181 {
182 if (mVertexDeclCache[i].lruCount < lastCache->lruCount)
183 {
184 lastCache = &mVertexDeclCache[i];
185 }
186 }
187
188 if (lastCache->vertexDeclaration != NULL)
189 {
190 lastCache->vertexDeclaration->Release();
191 lastCache->vertexDeclaration = NULL;
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
205void 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}