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 }