/*
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.software;
import static jpcsp.graphics.GeCommands.CMAT_FLAG_AMBIENT;
import static jpcsp.graphics.GeCommands.CMAT_FLAG_DIFFUSE;
import static jpcsp.graphics.GeCommands.CMAT_FLAG_SPECULAR;
import java.util.Arrays;
import java.util.HashMap;
import org.apache.log4j.Logger;
import jpcsp.Allegrex.compiler.RuntimeContext;
import jpcsp.graphics.GeContext;
import jpcsp.graphics.VideoEngine;
import jpcsp.util.ClassSpecializer;
import jpcsp.util.DurationStatistics;
import jpcsp.util.LongLongKey;
/**
* @author gid15
*
* Implementation of a filter compilation.
* The class RendererTemplate is specialized using fixed GE values/flags.
*/
public class FilterCompiler {
private static Logger log = VideoEngine.log;
private static FilterCompiler instance;
private HashMap<LongLongKey, RendererTemplate> compiledRenderers = new HashMap<LongLongKey, RendererTemplate>();
private static int classNameId = 0;
public static FilterCompiler getInstance() {
if (instance == null) {
instance = new FilterCompiler();
}
return instance;
}
private FilterCompiler() {
}
public RendererTemplate getCompiledRenderer(BasePrimitiveRenderer renderer, LongLongKey id, GeContext context) {
RendererTemplate compiledRenderer = compiledRenderers.get(id);
if (compiledRenderer == null) {
compiledRenderer = compileRenderer(renderer, id, context);
if (compiledRenderer != null) {
compiledRenderers.put(id, compiledRenderer);
}
}
return compiledRenderer;
}
private static String getNewCompiledRendererClassName() {
return String.format("Renderer%d", classNameId++);
}
private RendererTemplate compileRenderer(BasePrimitiveRenderer renderer, LongLongKey id, GeContext context) {
if (log.isInfoEnabled()) {
log.info(String.format("Compiling Renderer %s", id));
}
HashMap<String, Object> variables = new HashMap<String, Object>();
// All these variables have to be defined as static members in the class RendererTemplate.
variables.put("hasMemInt", Boolean.valueOf(RuntimeContext.hasMemoryInt()));
variables.put("transform2D", Boolean.valueOf(renderer.transform2D));
variables.put("clearMode", Boolean.valueOf(renderer.clearMode));
variables.put("clearModeColor", Boolean.valueOf(context.clearModeColor));
variables.put("clearModeStencil", Boolean.valueOf(context.clearModeStencil));
variables.put("clearModeDepth", Boolean.valueOf(context.clearModeDepth));
variables.put("needSourceDepthRead", Boolean.valueOf(renderer.needSourceDepthRead));
variables.put("needDestinationDepthRead", Boolean.valueOf(renderer.needDestinationDepthRead));
variables.put("needDepthWrite", Boolean.valueOf(renderer.needDepthWrite));
variables.put("needTextureUV", Boolean.valueOf(renderer.needTextureUV));
variables.put("simpleTextureUV", Boolean.valueOf(renderer.simpleTextureUV));
variables.put("swapTextureUV", Boolean.valueOf(renderer.swapTextureUV));
variables.put("needScissoringX", Boolean.valueOf(renderer.needScissoringX));
variables.put("needScissoringY", Boolean.valueOf(renderer.needScissoringY));
variables.put("nearZ", new Integer(renderer.nearZ));
variables.put("farZ", new Integer(renderer.farZ));
variables.put("colorTestFlagEnabled", Boolean.valueOf(context.colorTestFlag.isEnabled()));
variables.put("colorTestFunc", new Integer(context.colorTestFunc));
variables.put("alphaTestFlagEnabled", Boolean.valueOf(context.alphaTestFlag.isEnabled()));
variables.put("alphaFunc", new Integer(context.alphaFunc));
variables.put("alphaRef", new Integer(context.alphaRef));
variables.put("alphaMask", new Integer(context.alphaMask));
variables.put("stencilTestFlagEnabled", Boolean.valueOf(context.stencilTestFlag.isEnabled()));
variables.put("stencilFunc", new Integer(context.stencilFunc));
variables.put("stencilOpFail", new Integer(context.stencilOpFail));
variables.put("stencilOpZFail", new Integer(context.stencilOpZFail));
variables.put("stencilOpZPass", new Integer(context.stencilOpZPass));
variables.put("stencilRef", new Integer(context.stencilRef));
variables.put("depthTestFlagEnabled", Boolean.valueOf(context.depthTestFlag.isEnabled()));
variables.put("depthFunc", new Integer(context.depthFunc));
variables.put("blendFlagEnabled", Boolean.valueOf(context.blendFlag.isEnabled()));
variables.put("blendEquation", new Integer(context.blendEquation));
variables.put("blendSrc", new Integer(context.blend_src));
variables.put("blendDst", new Integer(context.blend_dst));
variables.put("sfix", new Integer(context.sfix));
variables.put("dfix", new Integer(context.dfix));
variables.put("colorLogicOpFlagEnabled", Boolean.valueOf(context.colorLogicOpFlag.isEnabled()));
variables.put("logicOp", new Integer(context.logicOp));
variables.put("colorMask", new Integer(PixelColor.getColor(context.colorMask)));
variables.put("depthMask", Boolean.valueOf(context.depthMask));
variables.put("textureFlagEnabled", Boolean.valueOf(context.textureFlag.isEnabled()));
variables.put("useVertexTexture", Boolean.valueOf(renderer.useVertexTexture));
variables.put("lightingFlagEnabled", Boolean.valueOf(context.lightingFlag.isEnabled()));
variables.put("sameVertexColor", Boolean.valueOf(renderer.sameVertexColor));
variables.put("setVertexPrimaryColor", Boolean.valueOf(renderer.setVertexPrimaryColor));
variables.put("primaryColorSetGlobally", Boolean.valueOf(renderer.primaryColorSetGlobally));
variables.put("isTriangle", Boolean.valueOf(renderer.isTriangle));
variables.put("matFlagAmbient", Boolean.valueOf((context.mat_flags & CMAT_FLAG_AMBIENT) != 0));
variables.put("matFlagDiffuse", Boolean.valueOf((context.mat_flags & CMAT_FLAG_DIFFUSE) != 0));
variables.put("matFlagSpecular", Boolean.valueOf((context.mat_flags & CMAT_FLAG_SPECULAR) != 0));
variables.put("useVertexColor", Boolean.valueOf(context.useVertexColor));
variables.put("textureColorDoubled", Boolean.valueOf(context.textureColorDoubled));
variables.put("lightMode", new Integer(context.lightMode));
variables.put("texMapMode", new Integer(context.tex_map_mode));
variables.put("texProjMapMode", new Integer(context.tex_proj_map_mode));
variables.put("texTranslateX", new Float(context.tex_translate_x));
variables.put("texTranslateY", new Float(context.tex_translate_y));
variables.put("texScaleX", new Float(context.tex_scale_x));
variables.put("texScaleY", new Float(context.tex_scale_y));
variables.put("texWrapS", new Integer(context.tex_wrap_s));
variables.put("texWrapT", new Integer(context.tex_wrap_t));
variables.put("textureFunc", new Integer(context.textureFunc));
variables.put("textureAlphaUsed", Boolean.valueOf(context.textureAlphaUsed));
variables.put("psm", new Integer(context.psm));
variables.put("texMagFilter", new Integer(context.tex_mag_filter));
variables.put("needTextureWrapU", Boolean.valueOf(renderer.needTextureWrapU));
variables.put("needTextureWrapV", Boolean.valueOf(renderer.needTextureWrapV));
variables.put("needSourceDepthClamp", Boolean.valueOf(renderer.needSourceDepthClamp));
variables.put("isLogTraceEnabled", Boolean.valueOf(renderer.isLogTraceEnabled));
variables.put("collectStatistics", Boolean.valueOf(DurationStatistics.collectStatistics));
variables.put("ditherFlagEnabled", Boolean.valueOf(context.ditherFlag.isEnabled()));
String specializedClassName = getNewCompiledRendererClassName();
ClassSpecializer cs = new ClassSpecializer();
Class<?> specializedClass = cs.specialize(specializedClassName, RendererTemplate.class, variables);
RendererTemplate compiledRenderer = null;
if (specializedClass != null) {
try {
compiledRenderer = (RendererTemplate) specializedClass.newInstance();
} catch (InstantiationException e) {
log.error("Error while instanciating compiled renderer", e);
} catch (IllegalAccessException e) {
log.error("Error while instanciating compiled renderer", e);
}
}
return compiledRenderer;
}
public static void exit() {
if (instance == null) {
return;
}
if (log.isInfoEnabled() && DurationStatistics.collectStatistics) {
DurationStatistics[] statistics = new DurationStatistics[instance.compiledRenderers.size()];
int n = 0;
for (RendererTemplate renderer : instance.compiledRenderers.values()) {
statistics[n++] = renderer.getStatistics();
}
Arrays.sort(statistics, 0, n);
for (int i = 0; i < n; i++) {
log.info(statistics[i]);
}
}
}
}