All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jme3.opencl.ProgramCache Maven / Gradle / Ivy

There is a newer version: 3.7.0-stable
Show newest version
/*
 * Copyright (c) 2009-2016 jMonkeyEngine
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
 *   may be used to endorse or promote products derived from this software
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.jme3.opencl;

import com.jme3.system.JmeSystem;
import com.jme3.util.BufferUtils;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Implements a simple cache system for program objects.
 * The program objects are saved persistently with {@link #saveToCache(java.lang.String, com.jme3.opencl.Program) }.
 * On the next run, the stored programs can then be loaded
 * with {@link #loadFromCache(java.lang.String, java.lang.String) }.
 * 
* The programs are identified by a unique id. The following format is recommended: * {@code id = .}. * * @author shaman */ public class ProgramCache { private static final Logger LOG = Logger.getLogger(ProgramCache.class.getName()); private static final String FILE_EXTENSION = ".clbin"; private final Context context; private final Device device; private final File tmpFolder; /** * Creates a "disabled" program cache, no caching is done. * {@link #loadFromCache(java.lang.String) } will always return {@code null} * and {@link #saveToCache(java.lang.String, com.jme3.opencl.Program) } does * nothing.
* Use this during development if you still modify your kernel code. * (Otherwise, you don't see the changes because you are still use the * cached version of your program) */ public ProgramCache() { this.context = null; this.device = null; this.tmpFolder = null; } /** * Creates a new program cache associated with the specified context and * devices. * The cached programs are built against the specified device and also * only the binaries linked to that device are stored. * @param context the OpenCL context * @param device the OpenCL device */ public ProgramCache(Context context, Device device) { this.context = context; this.device = device; if (JmeSystem.isLowPermissions()) { tmpFolder = null; } else { tmpFolder = JmeSystem.getStorageFolder(); } } protected String getCleanFileName(String id) { //http://stackoverflow.com/a/35591188/4053176 return id.replaceAll("[^a-zA-Z0-9.-]", "") + FILE_EXTENSION; } /** * Creates a new program cache using the first device from the specified * context. * @param context the context * @see #ProgramCache(com.jme3.opencl.Context, com.jme3.opencl.Device) */ public ProgramCache(Context context) { this(context, context.getDevices().get(0)); } /** * Loads the program from the cache and builds it against the current device. * You can pass additional build arguments with the parameter {@code buildArgs}. *

* The cached program is identified by the specified id. * This id must be unique, otherwise collisions within the cache occur. * Therefore, the following naming schema is recommended: * {@code id = .}. *

* If the program can't be loaded, built or any other exception happened, * {@code null} is returned. * * @param id the unique identifier of this program * @param buildArgs additional build arguments, can be {@code null} * @return the loaded and built program, or {@code null} * @see #saveToCache(java.lang.String, com.jme3.opencl.Program) */ public Program loadFromCache(String id, String buildArgs) { if (tmpFolder == null) { return null; //low permissions } //get file File file = new File(tmpFolder, getCleanFileName(id)); if (!file.exists()) { if (LOG.isLoggable(Level.FINE)) { LOG.log(Level.FINE, "Cache file {0} does not exist", file.getAbsolutePath()); } return null; } //load from file ByteBuffer bb; try { byte[] bytes = Files.readAllBytes(file.toPath()); bb = BufferUtils.createByteBuffer(bytes); } catch (IOException ex) { LOG.log(Level.FINE, "Unable to read cache file", ex); return null; } //create program Program program; try { program = context.createProgramFromBinary(bb, device); } catch (OpenCLException ex) { LOG.log(Level.FINE, "Unable to create program from binary", ex); return null; } //build program try { program.build(buildArgs, device); } catch (OpenCLException ex) { LOG.log(Level.FINE, "Unable to build program", ex); return null; } //done return program; } /** * Calls {@link #loadFromCache(java.lang.String, java.lang.String) } * with the additional build arguments set to {@code ""}. * @param id a unique identifier of the program * @return the loaded and built program or {@code null} if this * program could not be loaded from the cache * @see #loadFromCache(java.lang.String, java.lang.String) */ public Program loadFromCache(String id) { return loadFromCache(id, ""); } /** * Saves the specified program in the cache. * The parameter {@code id} denotes the name of the program. Under this id, * the program is then loaded again by {@link #loadFromCache(java.lang.String, java.lang.String) }. *
* The id must be unique, otherwise collisions within the cache occur. * Therefore, the following naming schema is recommended: * {@code id = .}. * * @param id the program id * @param program the program to store in the cache */ public void saveToCache(String id, Program program) { if (tmpFolder == null) { return; //low permissions } //get file File file = new File(tmpFolder, getCleanFileName(id)); //get binaries ByteBuffer bb; try { bb = program.getBinary(device); } catch (UnsupportedOperationException | OpenCLException ex) { LOG.log(Level.WARNING, "Unable to retrieve the program binaries", ex); return; } byte[] bytes = new byte[bb.remaining()]; bb.get(bytes); //save try { Files.write(file.toPath(), bytes); } catch (IOException ex) { LOG.log(Level.WARNING, "Unable to save program binaries to the cache", ex); } } /** * Clears the cache. * All saved program binaries are deleted. */ public void clearCache() { if (tmpFolder == null) { return; //low permissions } for (File file : tmpFolder.listFiles()) { if (file.isFile() && file.getName().endsWith(FILE_EXTENSION)) { file.delete(); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy