blob: 899baddddf015f732446e0122370ad1e1135f0ba [file] [log] [blame]
shannon.woods@transgaming.combdf2d802013-02-28 23:16:20 +00001#include "precompiled.h"
daniel@transgaming.com70a219b2012-11-28 21:00:08 +00002//
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"
Jamie Madill87939712013-07-02 11:57:01 -040011#include "libGLESv2/VertexAttribute.h"
daniel@transgaming.com4150d362012-12-20 21:07:43 +000012#include "libGLESv2/renderer/VertexBuffer9.h"
daniel@transgaming.com70a219b2012-11-28 21:00:08 +000013#include "libGLESv2/renderer/VertexDeclarationCache.h"
14
15namespace rx
16{
17
18VertexDeclarationCache::VertexDeclarationCache() : mMaxLru(0)
19{
20 for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
21 {
22 mVertexDeclCache[i].vertexDeclaration = NULL;
23 mVertexDeclCache[i].lruCount = 0;
24 }
25
26 for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
27 {
28 mAppliedVBs[i].serial = 0;
29 }
30
31 mLastSetVDecl = NULL;
32 mInstancingEnabled = true;
33}
34
35VertexDeclarationCache::~VertexDeclarationCache()
36{
37 for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
38 {
Geoff Langea228632013-07-30 15:17:12 -040039 SafeRelease(mVertexDeclCache[i].vertexDeclaration);
daniel@transgaming.com70a219b2012-11-28 21:00:08 +000040 }
41}
42
daniel@transgaming.com31240482012-11-28 21:06:41 +000043GLenum VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], gl::ProgramBinary *programBinary, GLsizei instances, GLsizei *repeatDraw)
daniel@transgaming.com70a219b2012-11-28 21:00:08 +000044{
45 *repeatDraw = 1;
46
47 int indexedAttribute = gl::MAX_VERTEX_ATTRIBS;
48 int instancedAttribute = gl::MAX_VERTEX_ATTRIBS;
49
50 if (instances > 0)
51 {
52 // Find an indexed attribute to be mapped to D3D stream 0
53 for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
54 {
55 if (attributes[i].active)
56 {
shannon.woods@transgaming.com51817d42013-01-25 21:55:57 +000057 if (indexedAttribute == gl::MAX_VERTEX_ATTRIBS && attributes[i].divisor == 0)
daniel@transgaming.com70a219b2012-11-28 21:00:08 +000058 {
shannon.woods@transgaming.com51817d42013-01-25 21:55:57 +000059 indexedAttribute = i;
daniel@transgaming.com70a219b2012-11-28 21:00:08 +000060 }
shannon.woods@transgaming.com51817d42013-01-25 21:55:57 +000061 else if (instancedAttribute == gl::MAX_VERTEX_ATTRIBS && attributes[i].divisor != 0)
daniel@transgaming.com70a219b2012-11-28 21:00:08 +000062 {
shannon.woods@transgaming.com51817d42013-01-25 21:55:57 +000063 instancedAttribute = i;
daniel@transgaming.com70a219b2012-11-28 21:00:08 +000064 }
shannon.woods@transgaming.com51817d42013-01-25 21:55:57 +000065 if (indexedAttribute != gl::MAX_VERTEX_ATTRIBS && instancedAttribute != gl::MAX_VERTEX_ATTRIBS)
66 break; // Found both an indexed and instanced attribute
daniel@transgaming.com70a219b2012-11-28 21:00:08 +000067 }
68 }
69
70 if (indexedAttribute == gl::MAX_VERTEX_ATTRIBS)
71 {
72 return GL_INVALID_OPERATION;
73 }
74 }
75
76 D3DVERTEXELEMENT9 elements[gl::MAX_VERTEX_ATTRIBS + 1];
77 D3DVERTEXELEMENT9 *element = &elements[0];
78
79 for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
80 {
81 if (attributes[i].active)
82 {
shannon.woods@transgaming.comdb1899c2013-02-28 23:08:33 +000083 // Directly binding the storage buffer is not supported for d3d9
84 ASSERT(attributes[i].storage == NULL);
85
daniel@transgaming.com70a219b2012-11-28 21:00:08 +000086 int stream = i;
87
88 if (instances > 0)
89 {
90 // Due to a bug on ATI cards we can't enable instancing when none of the attributes are instanced.
91 if (instancedAttribute == gl::MAX_VERTEX_ATTRIBS)
92 {
93 *repeatDraw = instances;
94 }
95 else
96 {
97 if (i == indexedAttribute)
98 {
99 stream = 0;
100 }
101 else if (i == 0)
102 {
103 stream = indexedAttribute;
104 }
105
106 UINT frequency = 1;
107
108 if (attributes[i].divisor == 0)
109 {
110 frequency = D3DSTREAMSOURCE_INDEXEDDATA | instances;
111 }
112 else
113 {
114 frequency = D3DSTREAMSOURCE_INSTANCEDATA | attributes[i].divisor;
115 }
116
117 device->SetStreamSourceFreq(stream, frequency);
118 mInstancingEnabled = true;
119 }
120 }
121
daniel@transgaming.com4150d362012-12-20 21:07:43 +0000122 VertexBuffer9 *vertexBuffer = VertexBuffer9::makeVertexBuffer9(attributes[i].vertexBuffer);
123
daniel@transgaming.com70a219b2012-11-28 21:00:08 +0000124 if (mAppliedVBs[stream].serial != attributes[i].serial ||
125 mAppliedVBs[stream].stride != attributes[i].stride ||
126 mAppliedVBs[stream].offset != attributes[i].offset)
127 {
daniel@transgaming.com4150d362012-12-20 21:07:43 +0000128 device->SetStreamSource(stream, vertexBuffer->getBuffer(), attributes[i].offset, attributes[i].stride);
daniel@transgaming.com70a219b2012-11-28 21:00:08 +0000129 mAppliedVBs[stream].serial = attributes[i].serial;
130 mAppliedVBs[stream].stride = attributes[i].stride;
131 mAppliedVBs[stream].offset = attributes[i].offset;
132 }
133
134 element->Stream = stream;
135 element->Offset = 0;
shannon.woods%transgaming.com@gtempaccount.comcf8d2f82013-04-13 03:37:34 +0000136 element->Type = vertexBuffer->getDeclType(*attributes[i].attribute);
daniel@transgaming.com70a219b2012-11-28 21:00:08 +0000137 element->Method = D3DDECLMETHOD_DEFAULT;
138 element->Usage = D3DDECLUSAGE_TEXCOORD;
139 element->UsageIndex = programBinary->getSemanticIndex(i);
140 element++;
141 }
142 }
143
144 if (instances == 0 || instancedAttribute == gl::MAX_VERTEX_ATTRIBS)
145 {
146 if (mInstancingEnabled)
147 {
148 for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
149 {
150 device->SetStreamSourceFreq(i, 1);
151 }
152
153 mInstancingEnabled = false;
154 }
155 }
156
157 static const D3DVERTEXELEMENT9 end = D3DDECL_END();
158 *(element++) = end;
159
160 for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
161 {
162 VertexDeclCacheEntry *entry = &mVertexDeclCache[i];
163 if (memcmp(entry->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9)) == 0 && entry->vertexDeclaration)
164 {
165 entry->lruCount = ++mMaxLru;
166 if(entry->vertexDeclaration != mLastSetVDecl)
167 {
168 device->SetVertexDeclaration(entry->vertexDeclaration);
169 mLastSetVDecl = entry->vertexDeclaration;
170 }
171
172 return GL_NO_ERROR;
173 }
174 }
175
176 VertexDeclCacheEntry *lastCache = mVertexDeclCache;
177
178 for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
179 {
180 if (mVertexDeclCache[i].lruCount < lastCache->lruCount)
181 {
182 lastCache = &mVertexDeclCache[i];
183 }
184 }
185
186 if (lastCache->vertexDeclaration != NULL)
187 {
Geoff Langea228632013-07-30 15:17:12 -0400188 SafeRelease(lastCache->vertexDeclaration);
daniel@transgaming.com70a219b2012-11-28 21:00:08 +0000189 // 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}