1 /* 2 * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.prism.d3d; 27 28 import com.sun.glass.ui.Screen; 29 import com.sun.javafx.geom.Rectangle; 30 import com.sun.javafx.geom.Vec3d; 31 import com.sun.javafx.geom.transform.BaseTransform; 32 import com.sun.javafx.geom.transform.GeneralTransform3D; 33 import com.sun.javafx.sg.prism.NGCamera; 34 import com.sun.javafx.sg.prism.NGDefaultCamera; 35 import com.sun.prism.CompositeMode; 36 import com.sun.prism.MeshView; 37 import com.sun.prism.RTTexture; 38 import com.sun.prism.RenderTarget; 39 import com.sun.prism.Texture; 40 import com.sun.prism.impl.PrismSettings; 41 import com.sun.prism.impl.VertexBuffer; 42 import com.sun.prism.impl.ps.BaseShaderContext; 43 import com.sun.prism.ps.Shader; 44 45 class D3DContext extends BaseShaderContext { 46 47 public static final int D3DERR_DEVICENOTRESET = 0x88760869; 48 public static final int D3DERR_DEVICELOST = 0x88760868; 49 public static final int E_FAIL = 0x80004005; 50 public static final int D3DERR_OUTOFVIDEOMEMORY = 0x8876017c; 51 public static final int D3D_OK = 0x0; 52 53 public static final int D3DCOMPMODE_CLEAR = 0; 54 public static final int D3DCOMPMODE_SRC = 1; 55 public static final int D3DCOMPMODE_SRCOVER = 2; 56 public static final int D3DCOMPMODE_DSTOUT = 3; 57 public static final int D3DCOMPMODE_ADD = 4; 58 59 public static final int D3DTADDRESS_NOP = 0; 60 public static final int D3DTADDRESS_WRAP = 1; 61 public static final int D3DTADDRESS_MIRROR = 2; 62 public static final int D3DTADDRESS_CLAMP = 3; 63 public static final int D3DTADDRESS_BORDER = 4; 64 65 // Use by face culling for 3D implementation 66 public final static int CULL_BACK = 110; 67 public final static int CULL_FRONT = 111; 68 public final static int CULL_NONE = 112; 69 /** 70 * WIN32 COM bool FAILED(HRESULT hr) macro synonym 71 * @param hr 72 * @return 73 */ 74 public static boolean FAILED(int hr) { 75 return hr<0; 76 } 77 78 // Temp. variables (Not Thread Safe) 79 private static GeneralTransform3D tempTx = new GeneralTransform3D(); 80 private static Vec3d tempVec3d = new Vec3d(); 81 82 private State state; 83 private boolean isLost = false; 84 85 private final long pContext; 86 87 NGCamera camera = null; 88 private int targetWidth = 0, targetHeight = 0; 89 90 private final D3DResourceFactory factory; 91 92 public static final int NUM_QUADS = PrismSettings.superShader ? 4096 : 256; 93 94 static VertexBuffer createVertexBuffer(long contextHandle) { 95 return new D3DVertexBuffer(contextHandle, NUM_QUADS); 96 } 97 98 D3DContext(long pContext, Screen screen, D3DResourceFactory factory) { 99 super(screen, factory, createVertexBuffer(pContext)); 100 this.pContext = pContext; 101 this.factory = factory; 102 } 103 104 @Override 105 public D3DResourceFactory getResourceFactory() { 106 return factory; 107 } 108 109 protected void initState() { 110 init(); 111 state = new State(); 112 validate(nSetBlendEnabled(pContext, D3DCOMPMODE_SRCOVER)); 113 validate(nSetDeviceParametersFor2D(pContext)); 114 } 115 116 long getContextHandle() { 117 return pContext; 118 } 119 120 /** 121 * Returns whether the context is lost. 122 * @return true if lost, false otherwise 123 */ 124 boolean isLost() { 125 return isLost; 126 } 127 128 /** 129 * Does D3D native return value validation for DEBUG interests 130 */ 131 static void validate(int res) { 132 if (PrismSettings.verbose && FAILED(res)) { 133 System.out.println("D3D hresult failed :" + hResultToString(res)); 134 new Exception("Stack trace").printStackTrace(System.out); 135 } 136 } 137 138 /** 139 * set device to lost state 140 */ 141 private void setLost() { 142 isLost = true; 143 } 144 145 /** 146 * Validates the device, sets the context lost 147 * status if necessary, and tries to restore the context if needed. 148 */ 149 boolean testLostStateAndReset() { 150 int hr = D3DResourceFactory.nTestCooperativeLevel(pContext); 151 152 if (hr == D3DERR_DEVICELOST) { 153 setLost(); 154 } 155 156 if (hr == D3DERR_DEVICENOTRESET) { 157 setLost(); 158 // disposing the lcd buffer because the device is about to be lost 159 disposeLCDBuffer(); 160 factory.notifyReset(); 161 162 hr = D3DResourceFactory.nResetDevice(pContext); 163 164 if (hr == D3D_OK) { 165 isLost = false; 166 initState(); 167 } 168 } 169 170 return hr == D3D_OK; 171 } 172 173 174 /** 175 * Validates result of present operation, 176 * sets the context lost status if necessary 177 */ 178 179 boolean validatePresent(int res) { 180 if (res == D3DERR_DEVICELOST || res == D3DERR_DEVICENOTRESET) { 181 setLost(); 182 } else { 183 validate(res); 184 } 185 186 return res == D3D_OK; 187 } 188 189 @Override 190 protected State updateRenderTarget(RenderTarget target, NGCamera camera, 191 boolean depthTest) { 192 long resourceHandle = ((D3DRenderTarget)target).getResourceHandle(); 193 int res = nSetRenderTarget(pContext, resourceHandle, depthTest, target.isAntiAliasing()); 194 validate(res); 195 // resetLastClip should be called only if render target was changed 196 // return value is S_FALSE (success with negative result) 197 // if render target wasn't changed 198 if (res == D3D_OK) { 199 resetLastClip(state); 200 } 201 202 this.camera = camera; 203 targetWidth = target.getPhysicalWidth(); 204 targetHeight = target.getPhysicalHeight(); 205 206 // Need to validate the camera before getting its computed data. 207 if (camera instanceof NGDefaultCamera) { 208 ((NGDefaultCamera) camera).validate(targetWidth, targetHeight); 209 } 210 211 // Set projection view matrix 212 tempTx = camera.getProjViewTx(tempTx); 213 res = nSetProjViewMatrix(pContext, depthTest, 214 tempTx.get(0), tempTx.get(1), tempTx.get(2), tempTx.get(3), 215 tempTx.get(4), tempTx.get(5), tempTx.get(6), tempTx.get(7), 216 tempTx.get(8), tempTx.get(9), tempTx.get(10), tempTx.get(11), 217 tempTx.get(12), tempTx.get(13), tempTx.get(14), tempTx.get(15)); 218 validate(res); 219 220 tempVec3d = camera.getPositionInWorld(tempVec3d); 221 // System.err.println("Camera position in world = " + tempVec3d); 222 res = nSetCameraPosition(pContext, tempVec3d.x, tempVec3d.y, tempVec3d.z); 223 224 return state; 225 } 226 227 @Override 228 protected void updateTexture(int texUnit, Texture tex) { 229 long texHandle; 230 boolean linear; 231 int wrapMode; 232 if (tex != null) { 233 D3DTexture d3dtex = (D3DTexture)tex; 234 texHandle = d3dtex.getNativeSourceHandle(); 235 linear = tex.getLinearFiltering(); 236 switch (tex.getWrapMode()) { 237 case CLAMP_NOT_NEEDED: 238 wrapMode = D3DTADDRESS_NOP; 239 break; 240 case CLAMP_TO_EDGE: 241 case CLAMP_TO_EDGE_SIMULATED: 242 case CLAMP_TO_ZERO_SIMULATED: 243 wrapMode = D3DTADDRESS_CLAMP; 244 break; 245 case CLAMP_TO_ZERO: 246 wrapMode = D3DTADDRESS_BORDER; 247 break; 248 case REPEAT: 249 case REPEAT_SIMULATED: 250 wrapMode = D3DTADDRESS_WRAP; 251 break; 252 default: 253 throw new InternalError("Unrecognized wrap mode: "+tex.getWrapMode()); 254 } 255 } else { 256 texHandle = 0L; 257 linear = false; 258 wrapMode = D3DTADDRESS_CLAMP; 259 } 260 validate(nSetTexture(pContext, texHandle, texUnit, linear, wrapMode)); 261 } 262 263 @Override 264 protected void updateShaderTransform(Shader shader, BaseTransform xform) { 265 int res; 266 if (xform == null || xform.isIdentity()) { 267 res = nResetTransform(pContext); 268 } else { 269 res = nSetTransform(pContext, 270 xform.getMxx(), xform.getMxy(), xform.getMxz(), xform.getMxt(), 271 xform.getMyx(), xform.getMyy(), xform.getMyz(), xform.getMyt(), 272 xform.getMzx(), xform.getMzy(), xform.getMzz(), xform.getMzt(), 273 0.0, 0.0, 0.0, 1.0); 274 } 275 validate(res); 276 } 277 278 protected void updateWorldTransform(BaseTransform xform) { 279 if ((xform == null) || xform.isIdentity()) { 280 nSetWorldTransformToIdentity(pContext); 281 } else { 282 nSetWorldTransform(pContext, 283 xform.getMxx(), xform.getMxy(), xform.getMxz(), xform.getMxt(), 284 xform.getMyx(), xform.getMyy(), xform.getMyz(), xform.getMyt(), 285 xform.getMzx(), xform.getMzy(), xform.getMzz(), xform.getMzt(), 286 0.0, 0.0, 0.0, 1.0); 287 } 288 } 289 290 @Override 291 protected void updateClipRect(Rectangle clipRect) { 292 int res; 293 if (clipRect == null || clipRect.isEmpty()) { 294 res = nResetClipRect(pContext); 295 } else { 296 int x1 = clipRect.x; 297 int y1 = clipRect.y; 298 int x2 = x1 + clipRect.width; 299 int y2 = y1 + clipRect.height; 300 res = nSetClipRect(pContext, x1, y1, x2, y2); 301 } 302 validate(res); 303 } 304 305 @Override 306 protected void updateCompositeMode(CompositeMode mode) { 307 int d3dmode; 308 switch (mode) { 309 case CLEAR: 310 d3dmode = D3DCOMPMODE_CLEAR; 311 break; 312 case SRC: 313 d3dmode = D3DCOMPMODE_SRC; 314 break; 315 case SRC_OVER: 316 d3dmode = D3DCOMPMODE_SRCOVER; 317 break; 318 case DST_OUT: 319 d3dmode = D3DCOMPMODE_DSTOUT; 320 break; 321 case ADD: 322 d3dmode = D3DCOMPMODE_ADD; 323 break; 324 default: 325 throw new InternalError("Unrecognized composite mode: "+mode); 326 } 327 validate(nSetBlendEnabled(pContext, d3dmode)); 328 } 329 330 D3DFrameStats getFrameStats(boolean reset, D3DFrameStats result) { 331 if (result == null) { 332 result = new D3DFrameStats(); 333 } 334 return nGetFrameStats(pContext, result, reset) ? result : null; 335 } 336 337 /* 338 * @param depthBuffer if true will create and attach a depthBuffer, 339 * if needed, of the same format as the render target. The depth test state 340 * is handled elsewhere. 341 */ 342 private static native int nSetRenderTarget(long pContext, long pDest, boolean depthBuffer, boolean msaa); 343 private static native int nSetTexture(long pContext, long pTex, int texUnit, 344 boolean linear, int wrapMode); 345 private static native int nResetTransform(long pContext); 346 private static native int nSetTransform(long pContext, 347 double m00, double m01, double m02, double m03, 348 double m10, double m11, double m12, double m13, 349 double m20, double m21, double m22, double m23, 350 double m30, double m31, double m32, double m33); 351 private static native void nSetWorldTransformToIdentity(long pContext); 352 private static native void nSetWorldTransform(long pContext, 353 double m00, double m01, double m02, double m03, 354 double m10, double m11, double m12, double m13, 355 double m20, double m21, double m22, double m23, 356 double m30, double m31, double m32, double m33); 357 private static native int nSetCameraPosition(long pContext, double x, double y, double z); 358 private static native int nSetProjViewMatrix(long pContext, boolean isOrtho, 359 double m00, double m01, double m02, double m03, 360 double m10, double m11, double m12, double m13, 361 double m20, double m21, double m22, double m23, 362 double m30, double m31, double m32, double m33); 363 private static native int nResetClipRect(long pContext); 364 private static native int nSetClipRect(long pContext, 365 int x1, int y1, int x2, int y2); 366 private static native int nSetBlendEnabled(long pContext, int mode); 367 private static native int nSetDeviceParametersFor2D(long pContext); 368 private static native int nSetDeviceParametersFor3D(long pContext); 369 370 private static native long nCreateD3DMesh(long pContext); 371 private static native void nReleaseD3DMesh(long pContext, long nativeHandle); 372 private static native boolean nBuildNativeGeometryShort(long pContext, long nativeHandle, 373 float[] vertexBuffer, int vertexBufferLength, short[] indexBuffer, int indexBufferLength); 374 private static native boolean nBuildNativeGeometryInt(long pContext, long nativeHandle, 375 float[] vertexBuffer, int vertexBufferLength, int[] indexBuffer, int indexBufferLength); 376 private static native long nCreateD3DPhongMaterial(long pContext); 377 private static native void nReleaseD3DPhongMaterial(long pContext, long nativeHandle); 378 private static native void nSetDiffuseColor(long pContext, long nativePhongMaterial, 379 float r, float g, float b, float a); 380 private static native void nSetSpecularColor(long pContext, long nativePhongMaterial, 381 boolean set, float r, float g, float b, float a); 382 private static native void nSetMap(long pContext, long nativePhongMaterial, 383 int mapType, long texID); 384 private static native long nCreateD3DMeshView(long pContext, long nativeMesh); 385 private static native void nReleaseD3DMeshView(long pContext, long nativeHandle); 386 private static native void nSetCullingMode(long pContext, long nativeMeshView, 387 int cullingMode); 388 private static native void nSetMaterial(long pContext, long nativeMeshView, 389 long nativePhongMaterialInfo); 390 private static native void nSetWireframe(long pContext, long nativeMeshView, 391 boolean wireframe); 392 private static native void nSetAmbientLight(long pContext, long nativeMeshView, 393 float r, float g, float b); 394 private static native void nSetPointLight(long pContext, long nativeMeshView, 395 int index, float x, float y, float z, float r, float g, float b, float w); 396 private static native void nRenderMeshView(long pContext, long nativeMeshView); 397 398 399 /* 400 * @param nSrcRTT must be valid native resource 401 * @param nDstRTT can be NULL if a valide render target is set 402 */ 403 private static native void nBlit(long pContext, long nSrcRTT, long nDstRTT, 404 int srcX0, int srcY0, int srcX1, int srcY1, 405 int dstX0, int dstY0, int dstX1, int dstY1); 406 407 private static native boolean nGetFrameStats(long pContext, 408 D3DFrameStats returnValue, boolean bReset); 409 410 private static native boolean nIsRTTVolatile(long contextHandle); 411 412 public boolean isRTTVolatile() { 413 return nIsRTTVolatile(pContext); 414 } 415 416 public static String hResultToString(long hResult) { 417 switch ((int)hResult) { 418 case (int)D3DERR_DEVICENOTRESET: 419 return "D3DERR_DEVICENOTRESET"; 420 case (int)D3DERR_DEVICELOST: 421 return "D3DERR_DEVICELOST"; 422 case (int)D3DERR_OUTOFVIDEOMEMORY: 423 return "D3DERR_OUTOFVIDEOMEMORY"; 424 case (int)D3D_OK: 425 return "D3D_OK"; 426 default: 427 return "D3D_ERROR " + Long.toHexString(hResult); 428 } 429 } 430 431 @Override 432 public void setDeviceParametersFor2D() { 433 nSetDeviceParametersFor2D(pContext); 434 } 435 436 @Override 437 protected void setDeviceParametersFor3D() { 438 nSetDeviceParametersFor3D(pContext); 439 } 440 441 long createD3DMesh() { 442 return nCreateD3DMesh(pContext); 443 } 444 445 // TODO: 3D - Should this be called dispose? 446 void releaseD3DMesh(long nativeHandle) { 447 nReleaseD3DMesh(pContext, nativeHandle); 448 } 449 450 boolean buildNativeGeometry(long nativeHandle, float[] vertexBuffer, int vertexBufferLength, 451 short[] indexBuffer, int indexBufferLength) { 452 return nBuildNativeGeometryShort(pContext, nativeHandle, vertexBuffer, 453 vertexBufferLength, indexBuffer, indexBufferLength); 454 } 455 456 boolean buildNativeGeometry(long nativeHandle, float[] vertexBuffer, int vertexBufferLength, 457 int[] indexBuffer, int indexBufferLength) { 458 return nBuildNativeGeometryInt(pContext, nativeHandle, vertexBuffer, 459 vertexBufferLength, indexBuffer, indexBufferLength); 460 } 461 462 long createD3DPhongMaterial() { 463 return nCreateD3DPhongMaterial(pContext); 464 } 465 466 // TODO: 3D - Should this be called dispose? 467 void releaseD3DPhongMaterial(long nativeHandle) { 468 nReleaseD3DPhongMaterial(pContext, nativeHandle); 469 } 470 471 void setDiffuseColor(long nativePhongMaterial, float r, float g, float b, float a) { 472 nSetDiffuseColor(pContext, nativePhongMaterial, r, g, b, a); 473 } 474 475 void setSpecularColor(long nativePhongMaterial, boolean set, float r, float g, float b, float a) { 476 nSetSpecularColor(pContext, nativePhongMaterial, set, r, g, b, a); 477 } 478 479 void setMap(long nativePhongMaterial, int mapType, long nativeTexture) { 480 nSetMap(pContext, nativePhongMaterial, mapType, nativeTexture); 481 } 482 483 long createD3DMeshView(long nativeMesh) { 484 return nCreateD3DMeshView(pContext, nativeMesh); 485 } 486 487 // TODO: 3D - Should this be called dispose? 488 void releaseD3DMeshView(long nativeMeshView) { 489 nReleaseD3DMeshView(pContext, nativeMeshView); 490 } 491 492 void setCullingMode(long nativeMeshView, int cullMode) { 493 int cm; 494 if (cullMode == MeshView.CULL_NONE) { 495 cm = CULL_NONE; 496 } else if (cullMode == MeshView.CULL_BACK) { 497 cm = CULL_BACK; 498 } else if (cullMode == MeshView.CULL_FRONT) { 499 cm = CULL_FRONT; 500 } else { 501 throw new IllegalArgumentException("illegal value for CullMode: " + cullMode); 502 } 503 nSetCullingMode(pContext, nativeMeshView, cm); 504 } 505 506 void setMaterial(long nativeMeshView, long nativePhongMaterial) { 507 nSetMaterial(pContext, nativeMeshView, nativePhongMaterial); 508 } 509 510 void setWireframe(long nativeMeshView, boolean wireframe) { 511 nSetWireframe(pContext, nativeMeshView, wireframe); 512 } 513 514 void setAmbientLight(long nativeMeshView, float r, float g, float b) { 515 nSetAmbientLight(pContext, nativeMeshView, r, g, b); 516 } 517 518 void setPointLight(long nativeMeshView, int index, float x, float y, float z, float r, float g, float b, float w) { 519 nSetPointLight(pContext, nativeMeshView, index, x, y, z, r, g, b, w); 520 } 521 522 void renderMeshView(long nativeMeshView, BaseTransform transformNoClone) { 523 updateWorldTransform(transformNoClone); 524 nRenderMeshView(pContext, nativeMeshView); 525 } 526 527 @Override 528 public void blit(RTTexture srcRTT, RTTexture dstRTT, 529 int srcX0, int srcY0, int srcX1, int srcY1, 530 int dstX0, int dstY0, int dstX1, int dstY1) { 531 long dstNativeHandle = dstRTT == null ? 0L : ((D3DTexture)dstRTT).getNativeSourceHandle(); 532 long srcNativeHandle = ((D3DTexture)srcRTT).getNativeSourceHandle(); 533 nBlit(pContext, srcNativeHandle, dstNativeHandle, 534 srcX0, srcY0, srcX1, srcY1, 535 dstX0, dstY0, dstX1, dstY1); 536 } 537 }