OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "GrVkGpu.h" | 8 #include "GrVkGpu.h" |
9 | 9 |
10 #include "GrContextOptions.h" | 10 #include "GrContextOptions.h" |
(...skipping 16 matching lines...) Expand all Loading... |
27 #include "GrVkRenderPass.h" | 27 #include "GrVkRenderPass.h" |
28 #include "GrVkResourceProvider.h" | 28 #include "GrVkResourceProvider.h" |
29 #include "GrVkTexture.h" | 29 #include "GrVkTexture.h" |
30 #include "GrVkTextureRenderTarget.h" | 30 #include "GrVkTextureRenderTarget.h" |
31 #include "GrVkTransferBuffer.h" | 31 #include "GrVkTransferBuffer.h" |
32 #include "GrVkVertexBuffer.h" | 32 #include "GrVkVertexBuffer.h" |
33 | 33 |
34 #include "SkConfig8888.h" | 34 #include "SkConfig8888.h" |
35 | 35 |
36 #include "vk/GrVkInterface.h" | 36 #include "vk/GrVkInterface.h" |
| 37 #include "vk/GrVkTypes.h" |
37 | 38 |
38 #define VK_CALL(X) GR_VK_CALL(this->vkInterface(), X) | 39 #define VK_CALL(X) GR_VK_CALL(this->vkInterface(), X) |
39 #define VK_CALL_RET(RET, X) GR_VK_CALL_RET(this->vkInterface(), RET, X) | 40 #define VK_CALL_RET(RET, X) GR_VK_CALL_RET(this->vkInterface(), RET, X) |
40 #define VK_CALL_ERRCHECK(X) GR_VK_CALL_ERRCHECK(this->vkInterface(), X) | 41 #define VK_CALL_ERRCHECK(X) GR_VK_CALL_ERRCHECK(this->vkInterface(), X) |
41 | 42 |
42 //////////////////////////////////////////////////////////////////////////////// | 43 //////////////////////////////////////////////////////////////////////////////// |
43 // Stuff used to set up a GrVkGpu secrectly for now. | 44 // Stuff used to set up a GrVkGpu secrectly for now. |
44 | 45 |
45 // For now the VkGpuCreate is using the same signature as GL. This is mostly for
ease of | 46 // For now the VkGpuCreate is using the same signature as GL. This is mostly for
ease of |
46 // hiding this code from offical skia. In the end the VkGpuCreate will not take
a GrBackendContext | 47 // hiding this code from offical skia. In the end the VkGpuCreate will not take
a GrBackendContext |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
188 VK_CALL(GetPhysicalDeviceMemoryProperties(physDev, &fPhysDevMemProps)); | 189 VK_CALL(GetPhysicalDeviceMemoryProperties(physDev, &fPhysDevMemProps)); |
189 | 190 |
190 } | 191 } |
191 | 192 |
192 GrVkGpu::~GrVkGpu() { | 193 GrVkGpu::~GrVkGpu() { |
193 shaderc_compiler_release(fCompiler); | 194 shaderc_compiler_release(fCompiler); |
194 fCurrentCmdBuffer->end(this); | 195 fCurrentCmdBuffer->end(this); |
195 fCurrentCmdBuffer->unref(this); | 196 fCurrentCmdBuffer->unref(this); |
196 | 197 |
197 // wait for all commands to finish | 198 // wait for all commands to finish |
198 VK_CALL(QueueWaitIdle(fQueue)); | 199 VkResult res = VK_CALL(QueueWaitIdle(fQueue)); |
| 200 SkASSERT(res == VK_SUCCESS); |
199 | 201 |
200 // must call this just before we destroy the VkDevice | 202 // must call this just before we destroy the VkDevice |
201 fResourceProvider.destroyResources(); | 203 fResourceProvider.destroyResources(); |
202 | 204 |
203 VK_CALL(DestroyCommandPool(fDevice, fCmdPool, nullptr)); | 205 VK_CALL(DestroyCommandPool(fDevice, fCmdPool, nullptr)); |
204 VK_CALL(DestroyDevice(fDevice, nullptr)); | 206 VK_CALL(DestroyDevice(fDevice, nullptr)); |
205 VK_CALL(DestroyInstance(fVkInstance, nullptr)); | 207 VK_CALL(DestroyInstance(fVkInstance, nullptr)); |
206 } | 208 } |
207 | 209 |
208 /////////////////////////////////////////////////////////////////////////////// | 210 /////////////////////////////////////////////////////////////////////////////// |
(...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
575 | 577 |
576 if (0 == desc.fTextureHandle) { | 578 if (0 == desc.fTextureHandle) { |
577 return nullptr; | 579 return nullptr; |
578 } | 580 } |
579 | 581 |
580 int maxSize = this->caps()->maxTextureSize(); | 582 int maxSize = this->caps()->maxTextureSize(); |
581 if (desc.fWidth > maxSize || desc.fHeight > maxSize) { | 583 if (desc.fWidth > maxSize || desc.fHeight > maxSize) { |
582 return nullptr; | 584 return nullptr; |
583 } | 585 } |
584 | 586 |
585 // TODO: determine what format Chrome will actually send us and turn it into
a Resource | 587 const GrVkTextureInfo* info = reinterpret_cast<const GrVkTextureInfo*>(desc.
fTextureHandle); |
586 GrVkImage::Resource* imageRsrc = reinterpret_cast<GrVkImage::Resource*>(desc
.fTextureHandle); | 588 if (VK_NULL_HANDLE == info->fImage || VK_NULL_HANDLE == info->fAlloc) { |
| 589 return nullptr; |
| 590 } |
587 | 591 |
588 GrGpuResource::LifeCycle lifeCycle = (kAdopt_GrWrapOwnership == ownership) | 592 GrGpuResource::LifeCycle lifeCycle = (kAdopt_GrWrapOwnership == ownership) |
589 ? GrGpuResource::kAdopted_LifeCycle | 593 ? GrGpuResource::kAdopted_LifeCycle |
590 : GrGpuResource::kBorrowed_LifeCycle; | 594 : GrGpuResource::kBorrowed_LifeCycle; |
591 | 595 |
592 GrSurfaceDesc surfDesc; | 596 GrSurfaceDesc surfDesc; |
593 // next line relies on GrBackendTextureDesc's flags matching GrTexture's | 597 // next line relies on GrBackendTextureDesc's flags matching GrTexture's |
594 surfDesc.fFlags = (GrSurfaceFlags)desc.fFlags; | 598 surfDesc.fFlags = (GrSurfaceFlags)desc.fFlags; |
595 surfDesc.fWidth = desc.fWidth; | 599 surfDesc.fWidth = desc.fWidth; |
596 surfDesc.fHeight = desc.fHeight; | 600 surfDesc.fHeight = desc.fHeight; |
597 surfDesc.fConfig = desc.fConfig; | 601 surfDesc.fConfig = desc.fConfig; |
598 surfDesc.fSampleCnt = SkTMin(desc.fSampleCnt, this->caps()->maxSampleCount()
); | 602 surfDesc.fSampleCnt = SkTMin(desc.fSampleCnt, this->caps()->maxSampleCount()
); |
599 bool renderTarget = SkToBool(desc.fFlags & kRenderTarget_GrBackendTextureFla
g); | 603 bool renderTarget = SkToBool(desc.fFlags & kRenderTarget_GrBackendTextureFla
g); |
600 // In GL, Chrome assumes all textures are BottomLeft | 604 // In GL, Chrome assumes all textures are BottomLeft |
601 // In VK, we don't have this restriction | 605 // In VK, we don't have this restriction |
602 surfDesc.fOrigin = resolve_origin(desc.fOrigin); | 606 surfDesc.fOrigin = resolve_origin(desc.fOrigin); |
603 | 607 |
604 GrVkTexture* texture = nullptr; | 608 GrVkTexture* texture = nullptr; |
605 if (renderTarget) { | 609 if (renderTarget) { |
606 texture = GrVkTextureRenderTarget::CreateWrappedTextureRenderTarget(this
, surfDesc, | 610 texture = GrVkTextureRenderTarget::CreateWrappedTextureRenderTarget(this
, surfDesc, |
607 life
Cycle, format, | 611 life
Cycle, format, |
608 imag
eRsrc); | 612 info
); |
609 } else { | 613 } else { |
610 texture = GrVkTexture::CreateWrappedTexture(this, surfDesc, lifeCycle, f
ormat, imageRsrc); | 614 texture = GrVkTexture::CreateWrappedTexture(this, surfDesc, lifeCycle, f
ormat, |
| 615 info); |
611 } | 616 } |
612 if (!texture) { | 617 if (!texture) { |
613 return nullptr; | 618 return nullptr; |
614 } | 619 } |
615 | 620 |
616 return texture; | 621 return texture; |
617 } | 622 } |
618 | 623 |
619 GrRenderTarget* GrVkGpu::onWrapBackendRenderTarget(const GrBackendRenderTargetDe
sc& wrapDesc, | 624 GrRenderTarget* GrVkGpu::onWrapBackendRenderTarget(const GrBackendRenderTargetDe
sc& wrapDesc, |
620 GrWrapOwnership ownership) { | 625 GrWrapOwnership ownership) { |
621 | 626 |
622 // TODO: determine what format Chrome will actually send us and turn it into
a Resource | 627 const GrVkTextureInfo* info = |
623 GrVkImage::Resource* imageRsrc = | 628 reinterpret_cast<const GrVkTextureInfo*>(wrapDesc.fRenderTargetHandle); |
624 reinterpret_cast<GrVkImage::Resource*>(wrapDesc.fRenderTargetHandle); | 629 if (VK_NULL_HANDLE == info->fImage || |
| 630 (VK_NULL_HANDLE == info->fAlloc && kAdopt_GrWrapOwnership == ownership))
{ |
| 631 return nullptr; |
| 632 } |
625 | 633 |
626 GrGpuResource::LifeCycle lifeCycle = (kAdopt_GrWrapOwnership == ownership) | 634 GrGpuResource::LifeCycle lifeCycle = (kAdopt_GrWrapOwnership == ownership) |
627 ? GrGpuResource::kAdopted_LifeCycle | 635 ? GrGpuResource::kAdopted_LifeCycle |
628 : GrGpuResource::kBorrowed_LifeCycle; | 636 : GrGpuResource::kBorrowed_LifeCycle; |
629 | 637 |
630 GrSurfaceDesc desc; | 638 GrSurfaceDesc desc; |
631 desc.fConfig = wrapDesc.fConfig; | 639 desc.fConfig = wrapDesc.fConfig; |
632 desc.fFlags = kCheckAllocation_GrSurfaceFlag; | 640 desc.fFlags = kCheckAllocation_GrSurfaceFlag; |
633 desc.fWidth = wrapDesc.fWidth; | 641 desc.fWidth = wrapDesc.fWidth; |
634 desc.fHeight = wrapDesc.fHeight; | 642 desc.fHeight = wrapDesc.fHeight; |
635 desc.fSampleCnt = SkTMin(wrapDesc.fSampleCnt, this->caps()->maxSampleCount()
); | 643 desc.fSampleCnt = SkTMin(wrapDesc.fSampleCnt, this->caps()->maxSampleCount()
); |
636 | 644 |
637 desc.fOrigin = resolve_origin(wrapDesc.fOrigin); | 645 desc.fOrigin = resolve_origin(wrapDesc.fOrigin); |
638 | 646 |
639 GrVkRenderTarget* tgt = GrVkRenderTarget::CreateWrappedRenderTarget(this, de
sc, | 647 GrVkRenderTarget* tgt = GrVkRenderTarget::CreateWrappedRenderTarget(this, de
sc, |
640 lifeCycl
e, imageRsrc); | 648 lifeCycl
e, |
| 649 info); |
641 if (tgt && wrapDesc.fStencilBits) { | 650 if (tgt && wrapDesc.fStencilBits) { |
642 if (!createStencilAttachmentForRenderTarget(tgt, desc.fWidth, desc.fHeig
ht)) { | 651 if (!createStencilAttachmentForRenderTarget(tgt, desc.fWidth, desc.fHeig
ht)) { |
643 tgt->unref(); | 652 tgt->unref(); |
644 return nullptr; | 653 return nullptr; |
645 } | 654 } |
646 } | 655 } |
647 return tgt; | 656 return tgt; |
648 } | 657 } |
649 | 658 |
650 //////////////////////////////////////////////////////////////////////////////// | 659 //////////////////////////////////////////////////////////////////////////////// |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
737 return 0; | 746 return 0; |
738 } | 747 } |
739 | 748 |
740 VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT; | 749 VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT; |
741 usageFlags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; | 750 usageFlags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; |
742 usageFlags |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; | 751 usageFlags |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; |
743 | 752 |
744 VkFlags memProps = (srcData && linearTiling) ? VK_MEMORY_PROPERTY_HOST_VISIB
LE_BIT : | 753 VkFlags memProps = (srcData && linearTiling) ? VK_MEMORY_PROPERTY_HOST_VISIB
LE_BIT : |
745 VK_MEMORY_PROPERTY_DEVICE_LOC
AL_BIT; | 754 VK_MEMORY_PROPERTY_DEVICE_LOC
AL_BIT; |
746 | 755 |
747 // This ImageDesc refers to the texture that will be read by the client. Thu
s even if msaa is | 756 VkImage image = VK_NULL_HANDLE; |
748 // requested, this ImageDesc describes the resolved texutre. Therefore we al
ways have samples set | 757 VkDeviceMemory alloc = VK_NULL_HANDLE; |
749 // to 1. | |
750 GrVkImage::ImageDesc imageDesc; | |
751 imageDesc.fImageType = VK_IMAGE_TYPE_2D; | |
752 imageDesc.fFormat = pixelFormat; | |
753 imageDesc.fWidth = w; | |
754 imageDesc.fHeight = h; | |
755 imageDesc.fLevels = 1; | |
756 imageDesc.fSamples = 1; | |
757 imageDesc.fImageTiling = linearTiling ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TI
LING_OPTIMAL; | |
758 imageDesc.fUsageFlags = usageFlags; | |
759 imageDesc.fMemProps = memProps; | |
760 | 758 |
761 const GrVkImage::Resource* imageRsrc = GrVkImage::CreateResource(this, image
Desc); | 759 VkImageTiling imageTiling = linearTiling ? VK_IMAGE_TILING_LINEAR : VK_IMAGE
_TILING_OPTIMAL; |
762 if (!imageRsrc) { | 760 VkImageLayout initialLayout = (VK_IMAGE_TILING_LINEAR == imageTiling) |
| 761 ? VK_IMAGE_LAYOUT_PREINITIALIZED |
| 762 : VK_IMAGE_LAYOUT_UNDEFINED; |
| 763 |
| 764 // Create Image |
| 765 VkSampleCountFlagBits vkSamples; |
| 766 if (!GrSampleCountToVkSampleCount(1, &vkSamples)) { |
763 return 0; | 767 return 0; |
764 } | 768 } |
765 | 769 |
| 770 const VkImageCreateInfo imageCreateInfo = { |
| 771 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // sType |
| 772 NULL, // pNext |
| 773 0, // VkImageCreateFlags |
| 774 VK_IMAGE_TYPE_2D, // VkImageType |
| 775 pixelFormat, // VkFormat |
| 776 { w, h, 1 }, // VkExtent3D |
| 777 1, // mipLevels |
| 778 1, // arrayLayers |
| 779 vkSamples, // samples |
| 780 imageTiling, // VkImageTiling |
| 781 usageFlags, // VkImageUsageFlags |
| 782 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode |
| 783 0, // queueFamilyCount |
| 784 0, // pQueueFamilyIndices |
| 785 initialLayout // initialLayout |
| 786 }; |
| 787 |
| 788 GR_VK_CALL_ERRCHECK(this->vkInterface(), CreateImage(this->device(), &imageC
reateInfo, nullptr, &image)); |
| 789 |
| 790 if (!GrVkMemory::AllocAndBindImageMemory(this, image, memProps, &alloc)) { |
| 791 VK_CALL(DestroyImage(this->device(), image, nullptr)); |
| 792 return 0; |
| 793 } |
| 794 |
766 if (srcData) { | 795 if (srcData) { |
767 if (linearTiling) { | 796 if (linearTiling) { |
768 const VkImageSubresource subres = { | 797 const VkImageSubresource subres = { |
769 VK_IMAGE_ASPECT_COLOR_BIT, | 798 VK_IMAGE_ASPECT_COLOR_BIT, |
770 0, // mipLevel | 799 0, // mipLevel |
771 0, // arraySlice | 800 0, // arraySlice |
772 }; | 801 }; |
773 VkSubresourceLayout layout; | 802 VkSubresourceLayout layout; |
774 VkResult err; | 803 VkResult err; |
775 | 804 |
776 const GrVkInterface* interface = this->vkInterface(); | 805 VK_CALL(GetImageSubresourceLayout(fDevice, image, &subres, &layout))
; |
777 | |
778 GR_VK_CALL(interface, GetImageSubresourceLayout(fDevice, | |
779 imageRsrc->fImage, | |
780 &subres, | |
781 &layout)); | |
782 | 806 |
783 void* mapPtr; | 807 void* mapPtr; |
784 err = GR_VK_CALL(interface, MapMemory(fDevice, | 808 err = VK_CALL(MapMemory(fDevice, alloc, 0, layout.rowPitch * h, 0, &
mapPtr)); |
785 imageRsrc->fAlloc, | |
786 0, | |
787 layout.rowPitch * h, | |
788 0, | |
789 &mapPtr)); | |
790 if (err) { | 809 if (err) { |
791 imageRsrc->unref(this); | 810 VK_CALL(FreeMemory(this->device(), alloc, nullptr)); |
| 811 VK_CALL(DestroyImage(this->device(), image, nullptr)); |
792 return 0; | 812 return 0; |
793 } | 813 } |
794 | 814 |
795 size_t bpp = GrBytesPerPixel(config); | 815 size_t bpp = GrBytesPerPixel(config); |
796 size_t rowCopyBytes = bpp * w; | 816 size_t rowCopyBytes = bpp * w; |
797 // If there is no padding on dst (layout.rowPitch) we can do a singl
e memcopy. | 817 // If there is no padding on dst (layout.rowPitch) we can do a singl
e memcopy. |
798 // This assumes the srcData comes in with no padding. | 818 // This assumes the srcData comes in with no padding. |
799 if (rowCopyBytes == layout.rowPitch) { | 819 if (rowCopyBytes == layout.rowPitch) { |
800 memcpy(mapPtr, srcData, rowCopyBytes * h); | 820 memcpy(mapPtr, srcData, rowCopyBytes * h); |
801 } else { | 821 } else { |
802 SkRectMemcpy(mapPtr, static_cast<size_t>(layout.rowPitch), srcDa
ta, w, rowCopyBytes, | 822 SkRectMemcpy(mapPtr, static_cast<size_t>(layout.rowPitch), srcDa
ta, rowCopyBytes, |
803 h); | 823 rowCopyBytes, h); |
804 } | 824 } |
805 GR_VK_CALL(interface, UnmapMemory(fDevice, imageRsrc->fAlloc)); | 825 VK_CALL(UnmapMemory(fDevice, alloc)); |
806 } else { | 826 } else { |
807 // TODO: Add support for copying to optimal tiling | 827 // TODO: Add support for copying to optimal tiling |
808 SkASSERT(false); | 828 SkASSERT(false); |
809 } | 829 } |
810 } | 830 } |
811 | 831 |
812 return (GrBackendObject)imageRsrc; | 832 GrVkTextureInfo* info = new GrVkTextureInfo; |
| 833 info->fImage = image; |
| 834 info->fAlloc = alloc; |
| 835 info->fImageTiling = imageTiling; |
| 836 info->fImageLayout = initialLayout; |
| 837 |
| 838 return (GrBackendObject)info; |
813 } | 839 } |
814 | 840 |
815 bool GrVkGpu::isTestingOnlyBackendTexture(GrBackendObject id) const { | 841 bool GrVkGpu::isTestingOnlyBackendTexture(GrBackendObject id) const { |
816 GrVkImage::Resource* backend = reinterpret_cast<GrVkImage::Resource*>(id); | 842 const GrVkTextureInfo* backend = reinterpret_cast<const GrVkTextureInfo*>(id
); |
817 | 843 |
818 if (backend && backend->fImage && backend->fAlloc) { | 844 if (backend && backend->fImage && backend->fAlloc) { |
819 VkMemoryRequirements req; | 845 VkMemoryRequirements req; |
820 memset(&req, 0, sizeof(req)); | 846 memset(&req, 0, sizeof(req)); |
821 GR_VK_CALL(this->vkInterface(), GetImageMemoryRequirements(fDevice, | 847 GR_VK_CALL(this->vkInterface(), GetImageMemoryRequirements(fDevice, |
822 backend->fIma
ge, | 848 backend->fIma
ge, |
823 &req)); | 849 &req)); |
824 // TODO: find a better check | 850 // TODO: find a better check |
825 // This will probably fail with a different driver | 851 // This will probably fail with a different driver |
826 return (req.size > 0) && (req.size <= 8192 * 8192); | 852 return (req.size > 0) && (req.size <= 8192 * 8192); |
827 } | 853 } |
828 | 854 |
829 return false; | 855 return false; |
830 } | 856 } |
831 | 857 |
832 void GrVkGpu::deleteTestingOnlyBackendTexture(GrBackendObject id, bool abandon)
{ | 858 void GrVkGpu::deleteTestingOnlyBackendTexture(GrBackendObject id, bool abandon)
{ |
833 GrVkImage::Resource* backend = reinterpret_cast<GrVkImage::Resource*>(id); | 859 const GrVkTextureInfo* backend = reinterpret_cast<const GrVkTextureInfo*>(id
); |
834 | 860 |
835 if (backend) { | 861 if (backend) { |
836 if (!abandon) { | 862 if (!abandon) { |
837 backend->unref(this); | 863 // something in the command buffer may still be using this, so force
submit |
838 } else { | 864 this->submitCommandBuffer(kForce_SyncQueue); |
839 backend->unrefAndAbandon(); | 865 |
| 866 VK_CALL(FreeMemory(this->device(), backend->fAlloc, nullptr)); |
| 867 VK_CALL(DestroyImage(this->device(), backend->fImage, nullptr)); |
840 } | 868 } |
| 869 delete backend; |
841 } | 870 } |
842 } | 871 } |
843 | 872 |
844 //////////////////////////////////////////////////////////////////////////////// | 873 //////////////////////////////////////////////////////////////////////////////// |
845 | 874 |
846 void GrVkGpu::addMemoryBarrier(VkPipelineStageFlags srcStageMask, | 875 void GrVkGpu::addMemoryBarrier(VkPipelineStageFlags srcStageMask, |
847 VkPipelineStageFlags dstStageMask, | 876 VkPipelineStageFlags dstStageMask, |
848 bool byRegion, | 877 bool byRegion, |
849 VkMemoryBarrier* barrier) const { | 878 VkMemoryBarrier* barrier) const { |
850 SkASSERT(fCurrentCmdBuffer); | 879 SkASSERT(fCurrentCmdBuffer); |
(...skipping 559 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1410 int set_a_break_pt_here = 9; | 1439 int set_a_break_pt_here = 9; |
1411 aglSwapBuffers(aglGetCurrentContext()); | 1440 aglSwapBuffers(aglGetCurrentContext()); |
1412 #elif defined(SK_BUILD_FOR_WIN32) | 1441 #elif defined(SK_BUILD_FOR_WIN32) |
1413 SwapBuf(); | 1442 SwapBuf(); |
1414 int set_a_break_pt_here = 9; | 1443 int set_a_break_pt_here = 9; |
1415 SwapBuf(); | 1444 SwapBuf(); |
1416 #endif | 1445 #endif |
1417 #endif | 1446 #endif |
1418 } | 1447 } |
1419 | 1448 |
OLD | NEW |