/*
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.RE.externalge;
import static jpcsp.Memory.isAddressGood;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import org.apache.log4j.Logger;
import jpcsp.Memory;
import jpcsp.Allegrex.compiler.RuntimeContext;
import jpcsp.util.DurationStatistics;
import jpcsp.util.Hash;
import jpcsp.util.Utilities;
/**
* @author gid15
*
*/
public class NativeCallbacks {
private static final Logger log = Logger.getLogger("NativeCallbacks");
private static DurationStatistics read32 = new DurationStatistics("read32");
private static DurationStatistics readByteBuffer = new DurationStatistics("readByteBuffer");
private static DurationStatistics writeByteBuffer = new DurationStatistics("writeByteBuffer");
private static DurationStatistics writeByteBufferArea = new DurationStatistics("writeByteBufferArea");
private static DurationStatistics getHashCode = new DurationStatistics("getHashCode");
// Array indexed by the log category
private static final Logger[] logs = new Logger[] {
log,
Logger.getLogger("externalge")
};
public static void exit() {
if (DurationStatistics.collectStatistics) {
log.info(read32.toString());
log.info(readByteBuffer.toString());
log.info(writeByteBuffer.toString());
log.info(getHashCode.toString());
}
}
private static Memory getMemory() {
return Memory.getInstance();
}
public static int read32(int address) {
if (DurationStatistics.collectStatistics) {
read32.start();
int value = getMemory().read32(address);
read32.end();
return value;
}
return getMemory().read32(address);
}
public static int read16(int address) {
return getMemory().read16(address);
}
public static int read8(int address) {
return getMemory().read8(address);
}
public static int readByteBuffer(int address, ByteBuffer destination, int length) {
readByteBuffer.start();
Buffer source = getMemory().getBuffer(address, length);
int offset = 0;
if (source != null) {
if (source instanceof IntBuffer) {
offset = address & 3;
}
Utilities.putBuffer(destination, source, ByteOrder.LITTLE_ENDIAN, length + offset);
}
readByteBuffer.end();
return offset;
}
public static void write32(int address, int value) {
getMemory().write32(address, value);
}
public static void write16(int address, short value) {
getMemory().write16(address, value);
}
public static void write8(int address, byte value) {
getMemory().write8(address, value);
}
public static void copy(int destination, int source, int length) {
getMemory().memcpy(destination, source, length);
}
public static void writeByteBuffer(int address, ByteBuffer source, int length) {
writeByteBuffer.start();
if (RuntimeContext.hasMemoryInt() && (address & 3) == 0 && (length & 3) == 0 && isAddressGood(address)) {
IntBuffer destination = IntBuffer.wrap(RuntimeContext.getMemoryInt(), (address & Memory.addressMask) >> 2, length >> 2);
source.order(ByteOrder.nativeOrder());
destination.put(source.asIntBuffer());
} else {
getMemory().copyToMemory(address, source, length);
}
writeByteBuffer.end();
}
public static void writeByteBufferArea(int address, ByteBuffer source, int bufferWidth, int width, int height) {
writeByteBufferArea.start();
if (RuntimeContext.hasMemoryInt() && (address & 3) == 0 && (width & 3) == 0 && (bufferWidth & 3) == 0 && isAddressGood(address)) {
int length = bufferWidth * height;
int destinationOffset = (address & Memory.addressMask) >> 2;
IntBuffer destination = IntBuffer.wrap(RuntimeContext.getMemoryInt(), destinationOffset, length >> 2);
source.order(ByteOrder.nativeOrder());
IntBuffer sourceInt = source.asIntBuffer();
int width4 = width >> 2;
int bufferWidth4 = bufferWidth >> 2;
for (int y = 0; y < height; y++) {
int offset = y * bufferWidth4;
sourceInt.limit(offset + width4);
sourceInt.position(offset);
destination.position(destinationOffset + offset);
destination.put(sourceInt);
}
} else {
Memory mem = getMemory();
for (int y = 0; y < height; y++) {
int offset = y * bufferWidth;
source.position(offset);
mem.copyToMemory(address + offset, source, width);
}
}
writeByteBufferArea.end();
}
public static int getHashCode(int hashCode, int addr, int lengthInBytes, int strideInBytes) {
getHashCode.start();
int value = Hash.getHashCode(hashCode, addr, lengthInBytes, strideInBytes);
getHashCode.end();
return value;
}
public static void log(int category, int level, String message) {
Logger log;
if (category >= 0 && category < logs.length) {
log = logs[category];
} else {
log = NativeCallbacks.log;
}
// Values matching jpcsp::log::Level defined in jpcsp.log.h
switch (level) {
case 0: // E_OFF
break;
case 1: // E_FATAL
log.fatal(message);
break;
case 2: // E_ERROR
log.error(message);
break;
case 3: // E_WARN
log.warn(message);
break;
case 4: // E_INFO
log.info(message);
break;
case 5: // E_DEBUG
log.debug(message);
break;
case 6: // E_TRACE
log.trace(message);
break;
case 7: // E_FORCE
log.info(message);
break;
default:
log.error(String.format("Unknown log level %d: %s", level, message));
break;
}
}
}