/*
This file is part of jpcsp.
Jpcsp is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Jpcsp is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Jpcsp. If not, see <http://www.gnu.org/licenses/>.
*/
package jpcsp.graphics;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import jpcsp.graphics.RE.IRenderingEngine;
import jpcsp.util.CpuDurationStatistics;
import jpcsp.util.DurationStatistics;
/**
* @author gid15
*
*/
public class VertexBufferManager {
private static VertexBufferManager instance;
private static final int maxSize = 1000;
private List<VertexBuffer> vertexBuffers = new LinkedList<VertexBuffer>();
private static final int allowedVertexGapSize = 4 * 1024;
private CpuDurationStatistics statistics = new CpuDurationStatistics("VertexBufferManager");
private HashMap<Integer, VertexBuffer> fastLookup = new HashMap<Integer, VertexBuffer>();
public static VertexBufferManager getInstance() {
if (instance == null) {
instance = new VertexBufferManager();
}
return instance;
}
public static void exit() {
if (instance != null) {
if (DurationStatistics.collectStatistics) {
VideoEngine.log.info(instance.statistics);
}
}
}
private static int getFastLookupKey(int address, int length) {
return address;
}
private static int getFastLookupKey(int address, int length, int stride) {
return address + (stride << 24);
}
public synchronized VertexBuffer getVertexBuffer(IRenderingEngine re, int address, int length, int stride, boolean strideAligned) {
statistics.start();
if (strideAligned) {
int fastLookupKey = getFastLookupKey(address, length, stride);
VertexBuffer vertexBuffer = fastLookup.get(fastLookupKey);
if (vertexBuffer != null) {
if (stride == vertexBuffer.getStride() && (vertexBuffer.getBufferOffset(address) % stride) == 0) {
if (vertexBuffer.isAddressInside(address, length, allowedVertexGapSize)) {
statistics.end();
return vertexBuffer;
}
}
}
boolean first = true;
for (ListIterator<VertexBuffer> lit = vertexBuffers.listIterator(); lit.hasNext(); ) {
vertexBuffer = lit.next();
if (stride == vertexBuffer.getStride() && (vertexBuffer.getBufferOffset(address) % stride) == 0) {
if (vertexBuffer.isAddressInside(address, length, allowedVertexGapSize)) {
if (!first) {
// Move the VertexBuffer to the head of the list
lit.remove();
vertexBuffers.add(0, vertexBuffer);
}
fastLookup.put(fastLookupKey, vertexBuffer);
statistics.end();
return vertexBuffer;
}
}
first = false;
}
} else {
int fastLookupKey = getFastLookupKey(address, length);
VertexBuffer vertexBuffer = fastLookup.get(fastLookupKey);
if (vertexBuffer != null) {
if (vertexBuffer.isAddressInside(address, length, allowedVertexGapSize)) {
statistics.end();
return vertexBuffer;
}
}
boolean first = true;
for (ListIterator<VertexBuffer> lit = vertexBuffers.listIterator(); lit.hasNext(); ) {
vertexBuffer = lit.next();
if (vertexBuffer.isAddressInside(address, length, allowedVertexGapSize)) {
if (!first) {
// Move the VertexBuffer to the head of the list
lit.remove();
vertexBuffers.add(0, vertexBuffer);
}
fastLookup.put(fastLookupKey, vertexBuffer);
statistics.end();
return vertexBuffer;
}
first = false;
}
}
VertexBuffer vertexBuffer = new VertexBuffer(address, stride);
vertexBuffers.add(0, vertexBuffer);
if (vertexBuffers.size() > maxSize && re != null) {
VertexBuffer toBeDeleted = vertexBuffers.remove(vertexBuffers.size() - 1);
if (re.isVertexArrayAvailable()) {
VertexArrayManager.getInstance().onVertexBufferDeleted(re, toBeDeleted);
}
toBeDeleted.delete(re);
}
statistics.end();
return vertexBuffer;
}
public synchronized void resetAddressAlreadyChecked() {
for (VertexBuffer vertexBuffer : vertexBuffers) {
vertexBuffer.resetAddressAlreadyChecked();
}
}
protected void displayStatistics() {
int length = 0;
for (VertexBuffer vertexBuffer : vertexBuffers) {
VideoEngine.log.info(vertexBuffer);
length += vertexBuffer.getLength();
}
VideoEngine.log.info(String.format("VertexBufferManager: %d buffers, total length %d", vertexBuffers.size(), length));
}
public synchronized void reset(IRenderingEngine re) {
for (ListIterator<VertexBuffer> lit = vertexBuffers.listIterator(); lit.hasNext(); ) {
VertexBuffer vertexBuffer = lit.next();
vertexBuffer.delete(re);
lit.remove();
}
}
}