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/VertexAttribute.h" 12#include "libGLESv2/renderer/d3d9/VertexBuffer9.h" 13#include "libGLESv2/renderer/d3d9/VertexDeclarationCache.h" 14#include "libGLESv2/renderer/d3d9/formatutils9.h" 15 16namespace rx 17{ 18 19VertexDeclarationCache::VertexDeclarationCache() : mMaxLru(0) 20{ 21 for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++) 22 { 23 mVertexDeclCache[i].vertexDeclaration = NULL; 24 mVertexDeclCache[i].lruCount = 0; 25 } 26 27 for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) 28 { 29 mAppliedVBs[i].serial = 0; 30 } 31 32 mLastSetVDecl = NULL; 33 mInstancingEnabled = true; 34} 35 36VertexDeclarationCache::~VertexDeclarationCache() 37{ 38 for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++) 39 { 40 SafeRelease(mVertexDeclCache[i].vertexDeclaration); 41 } 42} 43 44GLenum VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], gl::ProgramBinary *programBinary, GLsizei instances, GLsizei *repeatDraw) 45{ 46 *repeatDraw = 1; 47 48 int indexedAttribute = gl::MAX_VERTEX_ATTRIBS; 49 int instancedAttribute = gl::MAX_VERTEX_ATTRIBS; 50 51 if (instances > 0) 52 { 53 // Find an indexed attribute to be mapped to D3D stream 0 54 for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) 55 { 56 if (attributes[i].active) 57 { 58 if (indexedAttribute == gl::MAX_VERTEX_ATTRIBS && attributes[i].divisor == 0) 59 { 60 indexedAttribute = i; 61 } 62 else if (instancedAttribute == gl::MAX_VERTEX_ATTRIBS && attributes[i].divisor != 0) 63 { 64 instancedAttribute = i; 65 } 66 if (indexedAttribute != gl::MAX_VERTEX_ATTRIBS && instancedAttribute != gl::MAX_VERTEX_ATTRIBS) 67 break; // Found both an indexed and instanced attribute 68 } 69 } 70 71 if (indexedAttribute == gl::MAX_VERTEX_ATTRIBS) 72 { 73 return GL_INVALID_OPERATION; 74 } 75 } 76 77 D3DVERTEXELEMENT9 elements[gl::MAX_VERTEX_ATTRIBS + 1]; 78 D3DVERTEXELEMENT9 *element = &elements[0]; 79 80 for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) 81 { 82 if (attributes[i].active) 83 { 84 // Directly binding the storage buffer is not supported for d3d9 85 ASSERT(attributes[i].storage == NULL); 86 87 int stream = i; 88 89 if (instances > 0) 90 { 91 // Due to a bug on ATI cards we can't enable instancing when none of the attributes are instanced. 92 if (instancedAttribute == gl::MAX_VERTEX_ATTRIBS) 93 { 94 *repeatDraw = instances; 95 } 96 else 97 { 98 if (i == indexedAttribute) 99 { 100 stream = 0; 101 } 102 else if (i == 0) 103 { 104 stream = indexedAttribute; 105 } 106 107 UINT frequency = 1; 108 109 if (attributes[i].divisor == 0) 110 { 111 frequency = D3DSTREAMSOURCE_INDEXEDDATA | instances; 112 } 113 else 114 { 115 frequency = D3DSTREAMSOURCE_INSTANCEDATA | attributes[i].divisor; 116 } 117 118 device->SetStreamSourceFreq(stream, frequency); 119 mInstancingEnabled = true; 120 } 121 } 122 123 VertexBuffer9 *vertexBuffer = VertexBuffer9::makeVertexBuffer9(attributes[i].vertexBuffer); 124 125 if (mAppliedVBs[stream].serial != attributes[i].serial || 126 mAppliedVBs[stream].stride != attributes[i].stride || 127 mAppliedVBs[stream].offset != attributes[i].offset) 128 { 129 device->SetStreamSource(stream, vertexBuffer->getBuffer(), attributes[i].offset, attributes[i].stride); 130 mAppliedVBs[stream].serial = attributes[i].serial; 131 mAppliedVBs[stream].stride = attributes[i].stride; 132 mAppliedVBs[stream].offset = attributes[i].offset; 133 } 134 135 gl::VertexFormat vertexFormat(*attributes[i].attribute, GL_FLOAT); 136 137 element->Stream = stream; 138 element->Offset = 0; 139 element->Type = d3d9::GetNativeVertexFormat(vertexFormat); 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 SafeRelease(lastCache->vertexDeclaration); 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} 217