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/Context.h" 12 #include "libGLESv2/renderer/VertexBuffer9.h" 13 #include "libGLESv2/renderer/VertexDeclarationCache.h" 14 15 namespace rx 16 { 17 18 VertexDeclarationCache::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 35 VertexDeclarationCache::~VertexDeclarationCache() 36 { 37 for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++) 38 { 39 if (mVertexDeclCache[i].vertexDeclaration) 40 { 41 mVertexDeclCache[i].vertexDeclaration->Release(); 42 } 43 } 44 } 45 46 GLenum VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], gl::ProgramBinary *programBinary, GLsizei instances, GLsizei *repeatDraw) 47 { 48 *repeatDraw = 1; 49 50 int indexedAttribute = gl::MAX_VERTEX_ATTRIBS; 51 int instancedAttribute = gl::MAX_VERTEX_ATTRIBS; 52 53 if (instances > 0) 54 { 55 // Find an indexed attribute to be mapped to D3D stream 0 56 for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) 57 { 58 if (attributes[i].active) 59 { 60 if (indexedAttribute == gl::MAX_VERTEX_ATTRIBS && attributes[i].divisor == 0) 61 { 62 indexedAttribute = i; 63 } 64 else if (instancedAttribute == gl::MAX_VERTEX_ATTRIBS && attributes[i].divisor != 0) 65 { 66 instancedAttribute = i; 67 } 68 if (indexedAttribute != gl::MAX_VERTEX_ATTRIBS && instancedAttribute != gl::MAX_VERTEX_ATTRIBS) 69 break; // Found both an indexed and instanced attribute 70 } 71 } 72 73 if (indexedAttribute == gl::MAX_VERTEX_ATTRIBS) 74 { 75 return GL_INVALID_OPERATION; 76 } 77 } 78 79 D3DVERTEXELEMENT9 elements[gl::MAX_VERTEX_ATTRIBS + 1]; 80 D3DVERTEXELEMENT9 *element = &elements[0]; 81 82 for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) 83 { 84 if (attributes[i].active) 85 { 86 // Directly binding the storage buffer is not supported for d3d9 87 ASSERT(attributes[i].storage == NULL); 88 89 int stream = i; 90 91 if (instances > 0) 92 { 93 // Due to a bug on ATI cards we can't enable instancing when none of the attributes are instanced. 94 if (instancedAttribute == gl::MAX_VERTEX_ATTRIBS) 95 { 96 *repeatDraw = instances; 97 } 98 else 99 { 100 if (i == indexedAttribute) 101 { 102 stream = 0; 103 } 104 else if (i == 0) 105 { 106 stream = indexedAttribute; 107 } 108 109 UINT frequency = 1; 110 111 if (attributes[i].divisor == 0) 112 { 113 frequency = D3DSTREAMSOURCE_INDEXEDDATA | instances; 114 } 115 else 116 { 117 frequency = D3DSTREAMSOURCE_INSTANCEDATA | attributes[i].divisor; 118 } 119 120 device->SetStreamSourceFreq(stream, frequency); 121 mInstancingEnabled = true; 122 } 123 } 124 125 VertexBuffer9 *vertexBuffer = VertexBuffer9::makeVertexBuffer9(attributes[i].vertexBuffer); 126 127 if (mAppliedVBs[stream].serial != attributes[i].serial || 128 mAppliedVBs[stream].stride != attributes[i].stride || 129 mAppliedVBs[stream].offset != attributes[i].offset) 130 { 131 device->SetStreamSource(stream, vertexBuffer->getBuffer(), attributes[i].offset, attributes[i].stride); 132 mAppliedVBs[stream].serial = attributes[i].serial; 133 mAppliedVBs[stream].stride = attributes[i].stride; 134 mAppliedVBs[stream].offset = attributes[i].offset; 135 } 136 137 element->Stream = stream; 138 element->Offset = 0; 139 element->Type = attributes[i].attribute->mArrayEnabled ? vertexBuffer->getDeclType(*attributes[i].attribute) : D3DDECLTYPE_FLOAT4; 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 lastCache->vertexDeclaration->Release(); 192 lastCache->vertexDeclaration = NULL; 193 // mLastSetVDecl is set to the replacement, so we don't have to worry 194 // about it. 195 } 196 197 memcpy(lastCache->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9)); 198 device->CreateVertexDeclaration(elements, &lastCache->vertexDeclaration); 199 device->SetVertexDeclaration(lastCache->vertexDeclaration); 200 mLastSetVDecl = lastCache->vertexDeclaration; 201 lastCache->lruCount = ++mMaxLru; 202 203 return GL_NO_ERROR; 204 } 205 206 void VertexDeclarationCache::markStateDirty() 207 { 208 for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) 209 { 210 mAppliedVBs[i].serial = 0; 211 } 212 213 mLastSetVDecl = NULL; 214 mInstancingEnabled = true; // Forces it to be disabled when not used 215 } 216 217 } 218