blob: 8ed226de11329644a3f7ab600d0fc0eaad69d30a [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 {
85 int stream = i;
86
87 if (instances > 0)
88 {
89 // Due to a bug on ATI cards we can't enable instancing when none of the attributes are instanced.
90 if (instancedAttribute == gl::MAX_VERTEX_ATTRIBS)
91 {
92 *repeatDraw = instances;
93 }
94 else
95 {
96 if (i == indexedAttribute)
97 {
98 stream = 0;
99 }
100 else if (i == 0)
101 {
102 stream = indexedAttribute;
103 }
104
105 UINT frequency = 1;
106
107 if (attributes[i].divisor == 0)
108 {
109 frequency = D3DSTREAMSOURCE_INDEXEDDATA | instances;
110 }
111 else
112 {
113 frequency = D3DSTREAMSOURCE_INSTANCEDATA | attributes[i].divisor;
114 }
115
116 device->SetStreamSourceFreq(stream, frequency);
117 mInstancingEnabled = true;
118 }
119 }
120
daniel@transgaming.com4150d362012-12-20 21:07:43 +0000121 VertexBuffer9 *vertexBuffer = VertexBuffer9::makeVertexBuffer9(attributes[i].vertexBuffer);
122
daniel@transgaming.com70a219b2012-11-28 21:00:08 +0000123 if (mAppliedVBs[stream].serial != attributes[i].serial ||
124 mAppliedVBs[stream].stride != attributes[i].stride ||
125 mAppliedVBs[stream].offset != attributes[i].offset)
126 {
daniel@transgaming.com4150d362012-12-20 21:07:43 +0000127 device->SetStreamSource(stream, vertexBuffer->getBuffer(), attributes[i].offset, attributes[i].stride);
daniel@transgaming.com70a219b2012-11-28 21:00:08 +0000128 mAppliedVBs[stream].serial = attributes[i].serial;
129 mAppliedVBs[stream].stride = attributes[i].stride;
130 mAppliedVBs[stream].offset = attributes[i].offset;
131 }
132
133 element->Stream = stream;
134 element->Offset = 0;
daniel@transgaming.com4150d362012-12-20 21:07:43 +0000135 element->Type = attributes[i].attribute->mArrayEnabled ? vertexBuffer->getDeclType(*attributes[i].attribute) : D3DDECLTYPE_FLOAT4;
daniel@transgaming.com70a219b2012-11-28 21:00:08 +0000136 element->Method = D3DDECLMETHOD_DEFAULT;
137 element->Usage = D3DDECLUSAGE_TEXCOORD;
138 element->UsageIndex = programBinary->getSemanticIndex(i);
139 element++;
140 }
141 }
142
143 if (instances == 0 || instancedAttribute == gl::MAX_VERTEX_ATTRIBS)
144 {
145 if (mInstancingEnabled)
146 {
147 for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
148 {
149 device->SetStreamSourceFreq(i, 1);
150 }
151
152 mInstancingEnabled = false;
153 }
154 }
155
156 static const D3DVERTEXELEMENT9 end = D3DDECL_END();
157 *(element++) = end;
158
159 for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
160 {
161 VertexDeclCacheEntry *entry = &mVertexDeclCache[i];
162 if (memcmp(entry->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9)) == 0 && entry->vertexDeclaration)
163 {
164 entry->lruCount = ++mMaxLru;
165 if(entry->vertexDeclaration != mLastSetVDecl)
166 {
167 device->SetVertexDeclaration(entry->vertexDeclaration);
168 mLastSetVDecl = entry->vertexDeclaration;
169 }
170
171 return GL_NO_ERROR;
172 }
173 }
174
175 VertexDeclCacheEntry *lastCache = mVertexDeclCache;
176
177 for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
178 {
179 if (mVertexDeclCache[i].lruCount < lastCache->lruCount)
180 {
181 lastCache = &mVertexDeclCache[i];
182 }
183 }
184
185 if (lastCache->vertexDeclaration != NULL)
186 {
187 lastCache->vertexDeclaration->Release();
188 lastCache->vertexDeclaration = NULL;
189 // mLastSetVDecl is set to the replacement, so we don't have to worry
190 // about it.
191 }
192
193 memcpy(lastCache->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9));
194 device->CreateVertexDeclaration(elements, &lastCache->vertexDeclaration);
195 device->SetVertexDeclaration(lastCache->vertexDeclaration);
196 mLastSetVDecl = lastCache->vertexDeclaration;
197 lastCache->lruCount = ++mMaxLru;
198
199 return GL_NO_ERROR;
200}
201
202void VertexDeclarationCache::markStateDirty()
203{
204 for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
205 {
206 mAppliedVBs[i].serial = 0;
207 }
208
209 mLastSetVDecl = NULL;
210 mInstancingEnabled = true; // Forces it to be disabled when not used
211}
212
213}